2019-05-27 13:55:01 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-04-17 05:20:36 +07:00
|
|
|
/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
|
|
|
|
/*
|
|
|
|
Copyright (c) 2001, 2002 by D-Link Corporation
|
|
|
|
Written by Edward Peng.<edward_peng@dlink.com.tw>
|
|
|
|
Created 03-May-2001, base on Linux' sundance.c.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2007-08-13 07:45:41 +07:00
|
|
|
#define DRV_NAME "DL2000/TC902x-based linux driver"
|
2005-04-17 05:20:36 +07:00
|
|
|
#include "dl2k.h"
|
2006-05-15 23:44:43 +07:00
|
|
|
#include <linux/dma-mapping.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
#define dw32(reg, val) iowrite32(val, ioaddr + (reg))
|
|
|
|
#define dw16(reg, val) iowrite16(val, ioaddr + (reg))
|
|
|
|
#define dw8(reg, val) iowrite8(val, ioaddr + (reg))
|
|
|
|
#define dr32(reg) ioread32(ioaddr + (reg))
|
|
|
|
#define dr16(reg) ioread16(ioaddr + (reg))
|
|
|
|
#define dr8(reg) ioread8(ioaddr + (reg))
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#define MAX_UNITS 8
|
|
|
|
static int mtu[MAX_UNITS];
|
|
|
|
static int vlan[MAX_UNITS];
|
|
|
|
static int jumbo[MAX_UNITS];
|
|
|
|
static char *media[MAX_UNITS];
|
|
|
|
static int tx_flow=-1;
|
|
|
|
static int rx_flow=-1;
|
|
|
|
static int copy_thresh;
|
|
|
|
static int rx_coalesce=10; /* Rx frame count each interrupt */
|
|
|
|
static int rx_timeout=200; /* Rx DMA wait time in 640ns increments */
|
|
|
|
static int tx_coalesce=16; /* HW xmit count each TxDMAComplete */
|
|
|
|
|
|
|
|
|
|
|
|
MODULE_AUTHOR ("Edward Peng");
|
|
|
|
MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_param_array(mtu, int, NULL, 0);
|
|
|
|
module_param_array(media, charp, NULL, 0);
|
|
|
|
module_param_array(vlan, int, NULL, 0);
|
|
|
|
module_param_array(jumbo, int, NULL, 0);
|
|
|
|
module_param(tx_flow, int, 0);
|
|
|
|
module_param(rx_flow, int, 0);
|
|
|
|
module_param(copy_thresh, int, 0);
|
|
|
|
module_param(rx_coalesce, int, 0); /* Rx frame count each interrupt */
|
|
|
|
module_param(rx_timeout, int, 0); /* Rx DMA wait time in 64ns increments */
|
|
|
|
module_param(tx_coalesce, int, 0); /* HW xmit count each TxDMAComplete */
|
|
|
|
|
|
|
|
|
|
|
|
/* Enable the default interrupts */
|
|
|
|
#define DEFAULT_INTR (RxDMAComplete | HostError | IntRequested | TxDMAComplete| \
|
|
|
|
UpdateStats | LinkEvent)
|
2012-03-10 00:09:35 +07:00
|
|
|
|
|
|
|
static void dl2k_enable_int(struct netdev_private *np)
|
|
|
|
{
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
|
|
|
|
|
|
|
dw16(IntEnable, DEFAULT_INTR);
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-03-04 09:33:57 +07:00
|
|
|
static const int max_intrloop = 50;
|
|
|
|
static const int multicast_filter_limit = 0x40;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
static int rio_open (struct net_device *dev);
|
2017-10-17 07:29:11 +07:00
|
|
|
static void rio_timer (struct timer_list *t);
|
netdev: pass the stuck queue to the timeout handler
This allows incrementing the correct timeout statistic without any mess.
Down the road, devices can learn to reset just the specific queue.
The patch was generated with the following script:
use strict;
use warnings;
our $^I = '.bak';
my @work = (
["arch/m68k/emu/nfeth.c", "nfeth_tx_timeout"],
["arch/um/drivers/net_kern.c", "uml_net_tx_timeout"],
["arch/um/drivers/vector_kern.c", "vector_net_tx_timeout"],
["arch/xtensa/platforms/iss/network.c", "iss_net_tx_timeout"],
["drivers/char/pcmcia/synclink_cs.c", "hdlcdev_tx_timeout"],
["drivers/infiniband/ulp/ipoib/ipoib_main.c", "ipoib_timeout"],
["drivers/infiniband/ulp/ipoib/ipoib_main.c", "ipoib_timeout"],
["drivers/message/fusion/mptlan.c", "mpt_lan_tx_timeout"],
["drivers/misc/sgi-xp/xpnet.c", "xpnet_dev_tx_timeout"],
["drivers/net/appletalk/cops.c", "cops_timeout"],
["drivers/net/arcnet/arcdevice.h", "arcnet_timeout"],
["drivers/net/arcnet/arcnet.c", "arcnet_timeout"],
["drivers/net/arcnet/com20020.c", "arcnet_timeout"],
["drivers/net/ethernet/3com/3c509.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c515.c", "corkscrew_timeout"],
["drivers/net/ethernet/3com/3c574_cs.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c589_cs.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c59x.c", "vortex_tx_timeout"],
["drivers/net/ethernet/3com/3c59x.c", "vortex_tx_timeout"],
["drivers/net/ethernet/3com/typhoon.c", "typhoon_tx_timeout"],
["drivers/net/ethernet/8390/8390.h", "ei_tx_timeout"],
["drivers/net/ethernet/8390/8390.h", "eip_tx_timeout"],
["drivers/net/ethernet/8390/8390.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/8390p.c", "eip_tx_timeout"],
["drivers/net/ethernet/8390/ax88796.c", "ax_ei_tx_timeout"],
["drivers/net/ethernet/8390/axnet_cs.c", "axnet_tx_timeout"],
["drivers/net/ethernet/8390/etherh.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/hydra.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/mac8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/mcf8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/lib8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/ne2k-pci.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/pcnet_cs.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/smc-ultra.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/wd.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/zorro8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/adaptec/starfire.c", "tx_timeout"],
["drivers/net/ethernet/agere/et131x.c", "et131x_tx_timeout"],
["drivers/net/ethernet/allwinner/sun4i-emac.c", "emac_timeout"],
["drivers/net/ethernet/alteon/acenic.c", "ace_watchdog"],
["drivers/net/ethernet/amazon/ena/ena_netdev.c", "ena_tx_timeout"],
["drivers/net/ethernet/amd/7990.h", "lance_tx_timeout"],
["drivers/net/ethernet/amd/7990.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/a2065.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/am79c961a.c", "am79c961_timeout"],
["drivers/net/ethernet/amd/amd8111e.c", "amd8111e_tx_timeout"],
["drivers/net/ethernet/amd/ariadne.c", "ariadne_tx_timeout"],
["drivers/net/ethernet/amd/atarilance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/au1000_eth.c", "au1000_tx_timeout"],
["drivers/net/ethernet/amd/declance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/lance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/mvme147.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/ni65.c", "ni65_timeout"],
["drivers/net/ethernet/amd/nmclan_cs.c", "mace_tx_timeout"],
["drivers/net/ethernet/amd/pcnet32.c", "pcnet32_tx_timeout"],
["drivers/net/ethernet/amd/sunlance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/xgbe/xgbe-drv.c", "xgbe_tx_timeout"],
["drivers/net/ethernet/apm/xgene-v2/main.c", "xge_timeout"],
["drivers/net/ethernet/apm/xgene/xgene_enet_main.c", "xgene_enet_timeout"],
["drivers/net/ethernet/apple/macmace.c", "mace_tx_timeout"],
["drivers/net/ethernet/atheros/ag71xx.c", "ag71xx_tx_timeout"],
["drivers/net/ethernet/atheros/alx/main.c", "alx_tx_timeout"],
["drivers/net/ethernet/atheros/atl1c/atl1c_main.c", "atl1c_tx_timeout"],
["drivers/net/ethernet/atheros/atl1e/atl1e_main.c", "atl1e_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl.c", "atlx_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl1.c", "atlx_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl2.c", "atl2_tx_timeout"],
["drivers/net/ethernet/broadcom/b44.c", "b44_tx_timeout"],
["drivers/net/ethernet/broadcom/bcmsysport.c", "bcm_sysport_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2.c", "bnx2_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnxt/bnxt.c", "bnxt_tx_timeout"],
["drivers/net/ethernet/broadcom/genet/bcmgenet.c", "bcmgenet_timeout"],
["drivers/net/ethernet/broadcom/sb1250-mac.c", "sbmac_tx_timeout"],
["drivers/net/ethernet/broadcom/tg3.c", "tg3_tx_timeout"],
["drivers/net/ethernet/calxeda/xgmac.c", "xgmac_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_main.c", "liquidio_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_vf_main.c", "liquidio_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c", "lio_vf_rep_tx_timeout"],
["drivers/net/ethernet/cavium/thunder/nicvf_main.c", "nicvf_tx_timeout"],
["drivers/net/ethernet/cirrus/cs89x0.c", "net_timeout"],
["drivers/net/ethernet/cisco/enic/enic_main.c", "enic_tx_timeout"],
["drivers/net/ethernet/cisco/enic/enic_main.c", "enic_tx_timeout"],
["drivers/net/ethernet/cortina/gemini.c", "gmac_tx_timeout"],
["drivers/net/ethernet/davicom/dm9000.c", "dm9000_timeout"],
["drivers/net/ethernet/dec/tulip/de2104x.c", "de_tx_timeout"],
["drivers/net/ethernet/dec/tulip/tulip_core.c", "tulip_tx_timeout"],
["drivers/net/ethernet/dec/tulip/winbond-840.c", "tx_timeout"],
["drivers/net/ethernet/dlink/dl2k.c", "rio_tx_timeout"],
["drivers/net/ethernet/dlink/sundance.c", "tx_timeout"],
["drivers/net/ethernet/emulex/benet/be_main.c", "be_tx_timeout"],
["drivers/net/ethernet/ethoc.c", "ethoc_tx_timeout"],
["drivers/net/ethernet/faraday/ftgmac100.c", "ftgmac100_tx_timeout"],
["drivers/net/ethernet/fealnx.c", "fealnx_tx_timeout"],
["drivers/net/ethernet/freescale/dpaa/dpaa_eth.c", "dpaa_tx_timeout"],
["drivers/net/ethernet/freescale/fec_main.c", "fec_timeout"],
["drivers/net/ethernet/freescale/fec_mpc52xx.c", "mpc52xx_fec_tx_timeout"],
["drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c", "fs_timeout"],
["drivers/net/ethernet/freescale/gianfar.c", "gfar_timeout"],
["drivers/net/ethernet/freescale/ucc_geth.c", "ucc_geth_timeout"],
["drivers/net/ethernet/fujitsu/fmvj18x_cs.c", "fjn_tx_timeout"],
["drivers/net/ethernet/google/gve/gve_main.c", "gve_tx_timeout"],
["drivers/net/ethernet/hisilicon/hip04_eth.c", "hip04_timeout"],
["drivers/net/ethernet/hisilicon/hix5hd2_gmac.c", "hix5hd2_net_timeout"],
["drivers/net/ethernet/hisilicon/hns/hns_enet.c", "hns_nic_net_timeout"],
["drivers/net/ethernet/hisilicon/hns3/hns3_enet.c", "hns3_nic_net_timeout"],
["drivers/net/ethernet/huawei/hinic/hinic_main.c", "hinic_tx_timeout"],
["drivers/net/ethernet/i825xx/82596.c", "i596_tx_timeout"],
["drivers/net/ethernet/i825xx/ether1.c", "ether1_timeout"],
["drivers/net/ethernet/i825xx/lib82596.c", "i596_tx_timeout"],
["drivers/net/ethernet/i825xx/sun3_82586.c", "sun3_82586_timeout"],
["drivers/net/ethernet/ibm/ehea/ehea_main.c", "ehea_tx_watchdog"],
["drivers/net/ethernet/ibm/emac/core.c", "emac_tx_timeout"],
["drivers/net/ethernet/ibm/emac/core.c", "emac_tx_timeout"],
["drivers/net/ethernet/ibm/ibmvnic.c", "ibmvnic_tx_timeout"],
["drivers/net/ethernet/intel/e100.c", "e100_tx_timeout"],
["drivers/net/ethernet/intel/e1000/e1000_main.c", "e1000_tx_timeout"],
["drivers/net/ethernet/intel/e1000e/netdev.c", "e1000_tx_timeout"],
["drivers/net/ethernet/intel/fm10k/fm10k_netdev.c", "fm10k_tx_timeout"],
["drivers/net/ethernet/intel/i40e/i40e_main.c", "i40e_tx_timeout"],
["drivers/net/ethernet/intel/iavf/iavf_main.c", "iavf_tx_timeout"],
["drivers/net/ethernet/intel/ice/ice_main.c", "ice_tx_timeout"],
["drivers/net/ethernet/intel/ice/ice_main.c", "ice_tx_timeout"],
["drivers/net/ethernet/intel/igb/igb_main.c", "igb_tx_timeout"],
["drivers/net/ethernet/intel/igbvf/netdev.c", "igbvf_tx_timeout"],
["drivers/net/ethernet/intel/ixgb/ixgb_main.c", "ixgb_tx_timeout"],
["drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c", "adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev);"],
["drivers/net/ethernet/intel/ixgbe/ixgbe_main.c", "ixgbe_tx_timeout"],
["drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c", "ixgbevf_tx_timeout"],
["drivers/net/ethernet/jme.c", "jme_tx_timeout"],
["drivers/net/ethernet/korina.c", "korina_tx_timeout"],
["drivers/net/ethernet/lantiq_etop.c", "ltq_etop_tx_timeout"],
["drivers/net/ethernet/marvell/mv643xx_eth.c", "mv643xx_eth_tx_timeout"],
["drivers/net/ethernet/marvell/pxa168_eth.c", "pxa168_eth_tx_timeout"],
["drivers/net/ethernet/marvell/skge.c", "skge_tx_timeout"],
["drivers/net/ethernet/marvell/sky2.c", "sky2_tx_timeout"],
["drivers/net/ethernet/marvell/sky2.c", "sky2_tx_timeout"],
["drivers/net/ethernet/mediatek/mtk_eth_soc.c", "mtk_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx4/en_netdev.c", "mlx4_en_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx4/en_netdev.c", "mlx4_en_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx5/core/en_main.c", "mlx5e_tx_timeout"],
["drivers/net/ethernet/micrel/ks8842.c", "ks8842_tx_timeout"],
["drivers/net/ethernet/micrel/ksz884x.c", "netdev_tx_timeout"],
["drivers/net/ethernet/microchip/enc28j60.c", "enc28j60_tx_timeout"],
["drivers/net/ethernet/microchip/encx24j600.c", "encx24j600_tx_timeout"],
["drivers/net/ethernet/natsemi/sonic.h", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/sonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/jazzsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/macsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/natsemi.c", "ns_tx_timeout"],
["drivers/net/ethernet/natsemi/ns83820.c", "ns83820_tx_timeout"],
["drivers/net/ethernet/natsemi/xtsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/neterion/s2io.h", "s2io_tx_watchdog"],
["drivers/net/ethernet/neterion/s2io.c", "s2io_tx_watchdog"],
["drivers/net/ethernet/neterion/vxge/vxge-main.c", "vxge_tx_watchdog"],
["drivers/net/ethernet/netronome/nfp/nfp_net_common.c", "nfp_net_tx_timeout"],
["drivers/net/ethernet/nvidia/forcedeth.c", "nv_tx_timeout"],
["drivers/net/ethernet/nvidia/forcedeth.c", "nv_tx_timeout"],
["drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c", "pch_gbe_tx_timeout"],
["drivers/net/ethernet/packetengines/hamachi.c", "hamachi_tx_timeout"],
["drivers/net/ethernet/packetengines/yellowfin.c", "yellowfin_tx_timeout"],
["drivers/net/ethernet/pensando/ionic/ionic_lif.c", "ionic_tx_timeout"],
["drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c", "netxen_tx_timeout"],
["drivers/net/ethernet/qlogic/qla3xxx.c", "ql3xxx_tx_timeout"],
["drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c", "qlcnic_tx_timeout"],
["drivers/net/ethernet/qualcomm/emac/emac.c", "emac_tx_timeout"],
["drivers/net/ethernet/qualcomm/qca_spi.c", "qcaspi_netdev_tx_timeout"],
["drivers/net/ethernet/qualcomm/qca_uart.c", "qcauart_netdev_tx_timeout"],
["drivers/net/ethernet/rdc/r6040.c", "r6040_tx_timeout"],
["drivers/net/ethernet/realtek/8139cp.c", "cp_tx_timeout"],
["drivers/net/ethernet/realtek/8139too.c", "rtl8139_tx_timeout"],
["drivers/net/ethernet/realtek/atp.c", "tx_timeout"],
["drivers/net/ethernet/realtek/r8169_main.c", "rtl8169_tx_timeout"],
["drivers/net/ethernet/renesas/ravb_main.c", "ravb_tx_timeout"],
["drivers/net/ethernet/renesas/sh_eth.c", "sh_eth_tx_timeout"],
["drivers/net/ethernet/renesas/sh_eth.c", "sh_eth_tx_timeout"],
["drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c", "sxgbe_tx_timeout"],
["drivers/net/ethernet/seeq/ether3.c", "ether3_timeout"],
["drivers/net/ethernet/seeq/sgiseeq.c", "timeout"],
["drivers/net/ethernet/sfc/efx.c", "efx_watchdog"],
["drivers/net/ethernet/sfc/falcon/efx.c", "ef4_watchdog"],
["drivers/net/ethernet/sgi/ioc3-eth.c", "ioc3_timeout"],
["drivers/net/ethernet/sgi/meth.c", "meth_tx_timeout"],
["drivers/net/ethernet/silan/sc92031.c", "sc92031_tx_timeout"],
["drivers/net/ethernet/sis/sis190.c", "sis190_tx_timeout"],
["drivers/net/ethernet/sis/sis900.c", "sis900_tx_timeout"],
["drivers/net/ethernet/smsc/epic100.c", "epic_tx_timeout"],
["drivers/net/ethernet/smsc/smc911x.c", "smc911x_timeout"],
["drivers/net/ethernet/smsc/smc9194.c", "smc_timeout"],
["drivers/net/ethernet/smsc/smc91c92_cs.c", "smc_tx_timeout"],
["drivers/net/ethernet/smsc/smc91x.c", "smc_timeout"],
["drivers/net/ethernet/stmicro/stmmac/stmmac_main.c", "stmmac_tx_timeout"],
["drivers/net/ethernet/sun/cassini.c", "cas_tx_timeout"],
["drivers/net/ethernet/sun/ldmvsw.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/niu.c", "niu_tx_timeout"],
["drivers/net/ethernet/sun/sunbmac.c", "bigmac_tx_timeout"],
["drivers/net/ethernet/sun/sungem.c", "gem_tx_timeout"],
["drivers/net/ethernet/sun/sunhme.c", "happy_meal_tx_timeout"],
["drivers/net/ethernet/sun/sunqe.c", "qe_tx_timeout"],
["drivers/net/ethernet/sun/sunvnet.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/sunvnet_common.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/sunvnet_common.h", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/synopsys/dwc-xlgmac-net.c", "xlgmac_tx_timeout"],
["drivers/net/ethernet/ti/cpmac.c", "cpmac_tx_timeout"],
["drivers/net/ethernet/ti/cpsw.c", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/cpsw_priv.c", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/cpsw_priv.h", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/davinci_emac.c", "emac_dev_tx_timeout"],
["drivers/net/ethernet/ti/netcp_core.c", "netcp_ndo_tx_timeout"],
["drivers/net/ethernet/ti/tlan.c", "tlan_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_net.h", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_net.c", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_wireless.c", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/spider_net.c", "spider_net_tx_timeout"],
["drivers/net/ethernet/toshiba/tc35815.c", "tc35815_tx_timeout"],
["drivers/net/ethernet/via/via-rhine.c", "rhine_tx_timeout"],
["drivers/net/ethernet/wiznet/w5100.c", "w5100_tx_timeout"],
["drivers/net/ethernet/wiznet/w5300.c", "w5300_tx_timeout"],
["drivers/net/ethernet/xilinx/xilinx_emaclite.c", "xemaclite_tx_timeout"],
["drivers/net/ethernet/xircom/xirc2ps_cs.c", "xirc_tx_timeout"],
["drivers/net/fjes/fjes_main.c", "fjes_tx_retry"],
["drivers/net/slip/slip.c", "sl_tx_timeout"],
["include/linux/usb/usbnet.h", "usbnet_tx_timeout"],
["drivers/net/usb/aqc111.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/ax88172a.c", "usbnet_tx_timeout"],
["drivers/net/usb/ax88179_178a.c", "usbnet_tx_timeout"],
["drivers/net/usb/catc.c", "catc_tx_timeout"],
["drivers/net/usb/cdc_mbim.c", "usbnet_tx_timeout"],
["drivers/net/usb/cdc_ncm.c", "usbnet_tx_timeout"],
["drivers/net/usb/dm9601.c", "usbnet_tx_timeout"],
["drivers/net/usb/hso.c", "hso_net_tx_timeout"],
["drivers/net/usb/int51x1.c", "usbnet_tx_timeout"],
["drivers/net/usb/ipheth.c", "ipheth_tx_timeout"],
["drivers/net/usb/kaweth.c", "kaweth_tx_timeout"],
["drivers/net/usb/lan78xx.c", "lan78xx_tx_timeout"],
["drivers/net/usb/mcs7830.c", "usbnet_tx_timeout"],
["drivers/net/usb/pegasus.c", "pegasus_tx_timeout"],
["drivers/net/usb/qmi_wwan.c", "usbnet_tx_timeout"],
["drivers/net/usb/r8152.c", "rtl8152_tx_timeout"],
["drivers/net/usb/rndis_host.c", "usbnet_tx_timeout"],
["drivers/net/usb/rtl8150.c", "rtl8150_tx_timeout"],
["drivers/net/usb/sierra_net.c", "usbnet_tx_timeout"],
["drivers/net/usb/smsc75xx.c", "usbnet_tx_timeout"],
["drivers/net/usb/smsc95xx.c", "usbnet_tx_timeout"],
["drivers/net/usb/sr9700.c", "usbnet_tx_timeout"],
["drivers/net/usb/sr9800.c", "usbnet_tx_timeout"],
["drivers/net/usb/usbnet.c", "usbnet_tx_timeout"],
["drivers/net/vmxnet3/vmxnet3_drv.c", "vmxnet3_tx_timeout"],
["drivers/net/wan/cosa.c", "cosa_net_timeout"],
["drivers/net/wan/farsync.c", "fst_tx_timeout"],
["drivers/net/wan/fsl_ucc_hdlc.c", "uhdlc_tx_timeout"],
["drivers/net/wan/lmc/lmc_main.c", "lmc_driver_timeout"],
["drivers/net/wan/x25_asy.c", "x25_asy_timeout"],
["drivers/net/wimax/i2400m/netdev.c", "i2400m_tx_timeout"],
["drivers/net/wireless/intel/ipw2x00/ipw2100.c", "ipw2100_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/main.c", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/orinoco_usb.c", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/orinoco.h", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_dev.c", "islpci_eth_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_eth.c", "islpci_eth_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_eth.h", "islpci_eth_tx_timeout"],
["drivers/net/wireless/marvell/mwifiex/main.c", "mwifiex_tx_timeout"],
["drivers/net/wireless/quantenna/qtnfmac/core.c", "qtnf_netdev_tx_timeout"],
["drivers/net/wireless/quantenna/qtnfmac/core.h", "qtnf_netdev_tx_timeout"],
["drivers/net/wireless/rndis_wlan.c", "usbnet_tx_timeout"],
["drivers/net/wireless/wl3501_cs.c", "wl3501_tx_timeout"],
["drivers/net/wireless/zydas/zd1201.c", "zd1201_tx_timeout"],
["drivers/s390/net/qeth_core.h", "qeth_tx_timeout"],
["drivers/s390/net/qeth_core_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l2_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l2_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l3_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l3_main.c", "qeth_tx_timeout"],
["drivers/staging/ks7010/ks_wlan_net.c", "ks_wlan_tx_timeout"],
["drivers/staging/qlge/qlge_main.c", "qlge_tx_timeout"],
["drivers/staging/rtl8192e/rtl8192e/rtl_core.c", "_rtl92e_tx_timeout"],
["drivers/staging/rtl8192u/r8192U_core.c", "tx_timeout"],
["drivers/staging/unisys/visornic/visornic_main.c", "visornic_xmit_timeout"],
["drivers/staging/wlan-ng/p80211netdev.c", "p80211knetdev_tx_timeout"],
["drivers/tty/n_gsm.c", "gsm_mux_net_tx_timeout"],
["drivers/tty/synclink.c", "hdlcdev_tx_timeout"],
["drivers/tty/synclink_gt.c", "hdlcdev_tx_timeout"],
["drivers/tty/synclinkmp.c", "hdlcdev_tx_timeout"],
["net/atm/lec.c", "lec_tx_timeout"],
["net/bluetooth/bnep/netdev.c", "bnep_net_timeout"]
);
for my $p (@work) {
my @pair = @$p;
my $file = $pair[0];
my $func = $pair[1];
print STDERR $file , ": ", $func,"\n";
our @ARGV = ($file);
while (<ARGV>) {
if (m/($func\s*\(struct\s+net_device\s+\*[A-Za-z_]?[A-Za-z-0-9_]*)(\))/) {
print STDERR "found $1+$2 in $file\n";
}
if (s/($func\s*\(struct\s+net_device\s+\*[A-Za-z_]?[A-Za-z-0-9_]*)(\))/$1, unsigned int txqueue$2/) {
print STDERR "$func found in $file\n";
}
print;
}
}
where the list of files and functions is simply from:
git grep ndo_tx_timeout, with manual addition of headers
in the rare cases where the function is from a header,
then manually changing the few places which actually
call ndo_tx_timeout.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Heiner Kallweit <hkallweit1@gmail.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Shannon Nelson <snelson@pensando.io>
Reviewed-by: Martin Habets <mhabets@solarflare.com>
changes from v9:
fixup a forward declaration
changes from v9:
more leftovers from v3 change
changes from v8:
fix up a missing direct call to timeout
rebased on net-next
changes from v7:
fixup leftovers from v3 change
changes from v6:
fix typo in rtl driver
changes from v5:
add missing files (allow any net device argument name)
changes from v4:
add a missing driver header
changes from v3:
change queue # to unsigned
Changes from v2:
added headers
Changes from v1:
Fix errors found by kbuild:
generalize the pattern a bit, to pick up
a couple of instances missed by the previous
version.
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-12-10 21:23:51 +07:00
|
|
|
static void rio_tx_timeout (struct net_device *dev, unsigned int txqueue);
|
2009-09-01 02:50:58 +07:00
|
|
|
static netdev_tx_t start_xmit (struct sk_buff *skb, struct net_device *dev);
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
|
|
|
static irqreturn_t rio_interrupt (int irq, void *dev_instance);
|
2005-04-17 05:20:36 +07:00
|
|
|
static void rio_free_tx (struct net_device *dev, int irq);
|
|
|
|
static void tx_error (struct net_device *dev, int tx_status);
|
|
|
|
static int receive_packet (struct net_device *dev);
|
|
|
|
static void rio_error (struct net_device *dev, int int_status);
|
|
|
|
static void set_multicast (struct net_device *dev);
|
|
|
|
static struct net_device_stats *get_stats (struct net_device *dev);
|
|
|
|
static int clear_stats (struct net_device *dev);
|
|
|
|
static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
|
|
|
|
static int rio_close (struct net_device *dev);
|
|
|
|
static int find_miiphy (struct net_device *dev);
|
|
|
|
static int parse_eeprom (struct net_device *dev);
|
2012-03-10 00:09:35 +07:00
|
|
|
static int read_eeprom (struct netdev_private *, int eep_addr);
|
2005-04-17 05:20:36 +07:00
|
|
|
static int mii_wait_link (struct net_device *dev, int wait);
|
|
|
|
static int mii_set_media (struct net_device *dev);
|
|
|
|
static int mii_get_media (struct net_device *dev);
|
|
|
|
static int mii_set_media_pcs (struct net_device *dev);
|
|
|
|
static int mii_get_media_pcs (struct net_device *dev);
|
|
|
|
static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
|
|
|
|
static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
|
|
|
|
u16 data);
|
|
|
|
|
2006-09-14 01:30:00 +07:00
|
|
|
static const struct ethtool_ops ethtool_ops;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-11-22 08:31:51 +07:00
|
|
|
static const struct net_device_ops netdev_ops = {
|
|
|
|
.ndo_open = rio_open,
|
|
|
|
.ndo_start_xmit = start_xmit,
|
|
|
|
.ndo_stop = rio_close,
|
|
|
|
.ndo_get_stats = get_stats,
|
|
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
|
|
.ndo_set_mac_address = eth_mac_addr,
|
2011-08-16 13:29:01 +07:00
|
|
|
.ndo_set_rx_mode = set_multicast,
|
2008-11-22 08:31:51 +07:00
|
|
|
.ndo_do_ioctl = rio_ioctl,
|
|
|
|
.ndo_tx_timeout = rio_tx_timeout,
|
|
|
|
};
|
|
|
|
|
2012-12-03 21:23:07 +07:00
|
|
|
static int
|
2005-04-17 05:20:36 +07:00
|
|
|
rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
|
{
|
|
|
|
struct net_device *dev;
|
|
|
|
struct netdev_private *np;
|
|
|
|
static int card_idx;
|
|
|
|
int chip_idx = ent->driver_data;
|
|
|
|
int err, irq;
|
2012-03-10 00:09:35 +07:00
|
|
|
void __iomem *ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
void *ring_space;
|
|
|
|
dma_addr_t ring_dma;
|
|
|
|
|
|
|
|
err = pci_enable_device (pdev);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
irq = pdev->irq;
|
|
|
|
err = pci_request_regions (pdev, "dl2k");
|
|
|
|
if (err)
|
|
|
|
goto err_out_disable;
|
|
|
|
|
|
|
|
pci_set_master (pdev);
|
2012-03-10 00:09:35 +07:00
|
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
dev = alloc_etherdev (sizeof (*np));
|
2012-03-10 00:09:35 +07:00
|
|
|
if (!dev)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto err_out_res;
|
|
|
|
SET_NETDEV_DEV(dev, &pdev->dev);
|
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
np = netdev_priv(dev);
|
|
|
|
|
|
|
|
/* IO registers range. */
|
|
|
|
ioaddr = pci_iomap(pdev, 0, 0);
|
|
|
|
if (!ioaddr)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto err_out_dev;
|
2012-03-10 00:09:35 +07:00
|
|
|
np->eeprom_addr = ioaddr;
|
|
|
|
|
|
|
|
#ifdef MEM_MAPPING
|
|
|
|
/* MM registers range. */
|
|
|
|
ioaddr = pci_iomap(pdev, 1, 0);
|
|
|
|
if (!ioaddr)
|
|
|
|
goto err_out_iounmap;
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
2012-03-10 00:09:35 +07:00
|
|
|
np->ioaddr = ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
np->chip_id = chip_idx;
|
|
|
|
np->pdev = pdev;
|
|
|
|
spin_lock_init (&np->tx_lock);
|
|
|
|
spin_lock_init (&np->rx_lock);
|
|
|
|
|
|
|
|
/* Parse manual configuration */
|
|
|
|
np->an_enable = 1;
|
|
|
|
np->tx_coalesce = 1;
|
|
|
|
if (card_idx < MAX_UNITS) {
|
|
|
|
if (media[card_idx] != NULL) {
|
|
|
|
np->an_enable = 0;
|
|
|
|
if (strcmp (media[card_idx], "auto") == 0 ||
|
2006-09-14 00:24:59 +07:00
|
|
|
strcmp (media[card_idx], "autosense") == 0 ||
|
2005-04-17 05:20:36 +07:00
|
|
|
strcmp (media[card_idx], "0") == 0 ) {
|
2006-09-14 00:24:59 +07:00
|
|
|
np->an_enable = 2;
|
2005-04-17 05:20:36 +07:00
|
|
|
} else if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
|
|
|
|
strcmp (media[card_idx], "4") == 0) {
|
|
|
|
np->speed = 100;
|
|
|
|
np->full_duplex = 1;
|
2009-12-03 14:58:21 +07:00
|
|
|
} else if (strcmp (media[card_idx], "100mbps_hd") == 0 ||
|
|
|
|
strcmp (media[card_idx], "3") == 0) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 100;
|
|
|
|
np->full_duplex = 0;
|
|
|
|
} else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
|
|
|
|
strcmp (media[card_idx], "2") == 0) {
|
|
|
|
np->speed = 10;
|
|
|
|
np->full_duplex = 1;
|
|
|
|
} else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
|
|
|
|
strcmp (media[card_idx], "1") == 0) {
|
|
|
|
np->speed = 10;
|
|
|
|
np->full_duplex = 0;
|
|
|
|
} else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
|
|
|
|
strcmp (media[card_idx], "6") == 0) {
|
|
|
|
np->speed=1000;
|
|
|
|
np->full_duplex=1;
|
|
|
|
} else if (strcmp (media[card_idx], "1000mbps_hd") == 0 ||
|
|
|
|
strcmp (media[card_idx], "5") == 0) {
|
|
|
|
np->speed = 1000;
|
|
|
|
np->full_duplex = 0;
|
|
|
|
} else {
|
|
|
|
np->an_enable = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (jumbo[card_idx] != 0) {
|
|
|
|
np->jumbo = 1;
|
|
|
|
dev->mtu = MAX_JUMBO;
|
|
|
|
} else {
|
|
|
|
np->jumbo = 0;
|
|
|
|
if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
|
|
|
|
dev->mtu = mtu[card_idx];
|
|
|
|
}
|
|
|
|
np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
|
|
|
|
vlan[card_idx] : 0;
|
|
|
|
if (rx_coalesce > 0 && rx_timeout > 0) {
|
|
|
|
np->rx_coalesce = rx_coalesce;
|
|
|
|
np->rx_timeout = rx_timeout;
|
|
|
|
np->coalesce = 1;
|
|
|
|
}
|
|
|
|
np->tx_flow = (tx_flow == 0) ? 0 : 1;
|
|
|
|
np->rx_flow = (rx_flow == 0) ? 0 : 1;
|
|
|
|
|
|
|
|
if (tx_coalesce < 1)
|
|
|
|
tx_coalesce = 1;
|
|
|
|
else if (tx_coalesce > TX_RING_SIZE-1)
|
|
|
|
tx_coalesce = TX_RING_SIZE - 1;
|
|
|
|
}
|
2008-11-22 08:31:51 +07:00
|
|
|
dev->netdev_ops = &netdev_ops;
|
2005-04-17 05:20:36 +07:00
|
|
|
dev->watchdog_timeo = TX_TIMEOUT;
|
2014-05-11 07:12:32 +07:00
|
|
|
dev->ethtool_ops = ðtool_ops;
|
2005-04-17 05:20:36 +07:00
|
|
|
#if 0
|
|
|
|
dev->features = NETIF_F_IP_CSUM;
|
|
|
|
#endif
|
2016-10-18 02:54:11 +07:00
|
|
|
/* MTU range: 68 - 1536 or 8000 */
|
|
|
|
dev->min_mtu = ETH_MIN_MTU;
|
|
|
|
dev->max_mtu = np->jumbo ? MAX_JUMBO : PACKET_SIZE;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
pci_set_drvdata (pdev, dev);
|
|
|
|
|
|
|
|
ring_space = pci_alloc_consistent (pdev, TX_TOTAL_SIZE, &ring_dma);
|
|
|
|
if (!ring_space)
|
|
|
|
goto err_out_iounmap;
|
2011-06-17 02:08:06 +07:00
|
|
|
np->tx_ring = ring_space;
|
2005-04-17 05:20:36 +07:00
|
|
|
np->tx_ring_dma = ring_dma;
|
|
|
|
|
|
|
|
ring_space = pci_alloc_consistent (pdev, RX_TOTAL_SIZE, &ring_dma);
|
|
|
|
if (!ring_space)
|
|
|
|
goto err_out_unmap_tx;
|
2011-06-17 02:08:06 +07:00
|
|
|
np->rx_ring = ring_space;
|
2005-04-17 05:20:36 +07:00
|
|
|
np->rx_ring_dma = ring_dma;
|
|
|
|
|
|
|
|
/* Parse eeprom data */
|
|
|
|
parse_eeprom (dev);
|
|
|
|
|
|
|
|
/* Find PHY address */
|
|
|
|
err = find_miiphy (dev);
|
|
|
|
if (err)
|
|
|
|
goto err_out_unmap_rx;
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Fiber device? */
|
2012-03-10 00:09:35 +07:00
|
|
|
np->phy_media = (dr16(ASICCtrl) & PhyMedia) ? 1 : 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
np->link_status = 0;
|
|
|
|
/* Set media and reset PHY */
|
|
|
|
if (np->phy_media) {
|
|
|
|
/* default Auto-Negotiation for fiber deivices */
|
|
|
|
if (np->an_enable == 2) {
|
|
|
|
np->an_enable = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Auto-Negotiation is mandatory for 1000BASE-T,
|
|
|
|
IEEE 802.3ab Annex 28D page 14 */
|
|
|
|
if (np->speed == 1000)
|
|
|
|
np->an_enable = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = register_netdev (dev);
|
|
|
|
if (err)
|
|
|
|
goto err_out_unmap_rx;
|
|
|
|
|
|
|
|
card_idx++;
|
|
|
|
|
2008-10-28 05:59:26 +07:00
|
|
|
printk (KERN_INFO "%s: %s, %pM, IRQ %d\n",
|
|
|
|
dev->name, np->name, dev->dev_addr, irq);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (tx_coalesce > 1)
|
2006-09-14 00:24:59 +07:00
|
|
|
printk(KERN_INFO "tx_coalesce:\t%d packets\n",
|
2005-04-17 05:20:36 +07:00
|
|
|
tx_coalesce);
|
|
|
|
if (np->coalesce)
|
2009-07-07 03:05:40 +07:00
|
|
|
printk(KERN_INFO
|
|
|
|
"rx_coalesce:\t%d packets\n"
|
|
|
|
"rx_timeout: \t%d ns\n",
|
2005-04-17 05:20:36 +07:00
|
|
|
np->rx_coalesce, np->rx_timeout*640);
|
|
|
|
if (np->vlan)
|
|
|
|
printk(KERN_INFO "vlan(id):\t%d\n", np->vlan);
|
|
|
|
return 0;
|
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
err_out_unmap_rx:
|
2005-04-17 05:20:36 +07:00
|
|
|
pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
|
2012-03-10 00:09:35 +07:00
|
|
|
err_out_unmap_tx:
|
2005-04-17 05:20:36 +07:00
|
|
|
pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
|
2012-03-10 00:09:35 +07:00
|
|
|
err_out_iounmap:
|
2005-04-17 05:20:36 +07:00
|
|
|
#ifdef MEM_MAPPING
|
2012-03-10 00:09:35 +07:00
|
|
|
pci_iounmap(pdev, np->ioaddr);
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
2012-03-10 00:09:35 +07:00
|
|
|
pci_iounmap(pdev, np->eeprom_addr);
|
|
|
|
err_out_dev:
|
2005-04-17 05:20:36 +07:00
|
|
|
free_netdev (dev);
|
2012-03-10 00:09:35 +07:00
|
|
|
err_out_res:
|
2005-04-17 05:20:36 +07:00
|
|
|
pci_release_regions (pdev);
|
2012-03-10 00:09:35 +07:00
|
|
|
err_out_disable:
|
2005-04-17 05:20:36 +07:00
|
|
|
pci_disable_device (pdev);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-10-06 07:19:47 +07:00
|
|
|
static int
|
2005-04-17 05:20:36 +07:00
|
|
|
find_miiphy (struct net_device *dev)
|
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
int i, phy_found = 0;
|
2017-11-01 15:57:37 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
np->phy_addr = 1;
|
|
|
|
|
|
|
|
for (i = 31; i >= 0; i--) {
|
|
|
|
int mii_status = mii_read (dev, i, 1);
|
|
|
|
if (mii_status != 0xffff && mii_status != 0x0000) {
|
|
|
|
np->phy_addr = i;
|
|
|
|
phy_found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!phy_found) {
|
|
|
|
printk (KERN_ERR "%s: No MII PHY found!\n", dev->name);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-06 07:19:47 +07:00
|
|
|
static int
|
2005-04-17 05:20:36 +07:00
|
|
|
parse_eeprom (struct net_device *dev)
|
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
int i, j;
|
|
|
|
u8 sromdata[256];
|
|
|
|
u8 *psib;
|
|
|
|
u32 crc;
|
|
|
|
PSROM_t psrom = (PSROM_t) sromdata;
|
|
|
|
|
|
|
|
int cid, next;
|
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
for (i = 0; i < 128; i++)
|
|
|
|
((__le16 *) sromdata)[i] = cpu_to_le16(read_eeprom(np, i));
|
|
|
|
|
2007-08-13 07:45:41 +07:00
|
|
|
if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) { /* D-Link Only */
|
|
|
|
/* Check CRC */
|
|
|
|
crc = ~ether_crc_le (256 - 4, sromdata);
|
2011-06-10 11:55:16 +07:00
|
|
|
if (psrom->crc != cpu_to_le32(crc)) {
|
2007-08-13 07:45:41 +07:00
|
|
|
printk (KERN_ERR "%s: EEPROM data CRC error.\n",
|
|
|
|
dev->name);
|
|
|
|
return -1;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set MAC address */
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
dev->dev_addr[i] = psrom->mac_addr[i];
|
|
|
|
|
2015-11-16 04:36:11 +07:00
|
|
|
if (np->chip_id == CHIP_IP1000A) {
|
|
|
|
np->led_mode = psrom->led_mode;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-13 07:45:41 +07:00
|
|
|
if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-06-30 23:25:18 +07:00
|
|
|
/* Parse Software Information Block */
|
2005-04-17 05:20:36 +07:00
|
|
|
i = 0x30;
|
|
|
|
psib = (u8 *) sromdata;
|
|
|
|
do {
|
|
|
|
cid = psib[i++];
|
|
|
|
next = psib[i++];
|
|
|
|
if ((cid == 0 && next == 0) || (cid == 0xff && next == 0xff)) {
|
|
|
|
printk (KERN_ERR "Cell data error\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
switch (cid) {
|
|
|
|
case 0: /* Format version */
|
|
|
|
break;
|
|
|
|
case 1: /* End of cell */
|
|
|
|
return 0;
|
|
|
|
case 2: /* Duplex Polarity */
|
|
|
|
np->duplex_polarity = psib[i];
|
2012-03-10 00:09:35 +07:00
|
|
|
dw8(PhyCtrl, dr8(PhyCtrl) | psib[i]);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
case 3: /* Wake Polarity */
|
|
|
|
np->wake_polarity = psib[i];
|
|
|
|
break;
|
|
|
|
case 9: /* Adapter description */
|
|
|
|
j = (next - i > 255) ? 255 : next - i;
|
|
|
|
memcpy (np->name, &(psib[i]), j);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
case 8: /* Reversed */
|
|
|
|
break;
|
|
|
|
default: /* Unknown cell */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
i = next;
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-16 04:36:11 +07:00
|
|
|
static void rio_set_led_mode(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
|
|
|
u32 mode;
|
|
|
|
|
|
|
|
if (np->chip_id != CHIP_IP1000A)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mode = dr32(ASICCtrl);
|
|
|
|
mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
|
|
|
|
|
|
|
|
if (np->led_mode & 0x01)
|
|
|
|
mode |= IPG_AC_LED_MODE;
|
|
|
|
if (np->led_mode & 0x02)
|
|
|
|
mode |= IPG_AC_LED_MODE_BIT_1;
|
|
|
|
if (np->led_mode & 0x08)
|
|
|
|
mode |= IPG_AC_LED_SPEED;
|
|
|
|
|
|
|
|
dw32(ASICCtrl, mode);
|
|
|
|
}
|
|
|
|
|
2015-11-20 02:13:04 +07:00
|
|
|
static inline dma_addr_t desc_to_dma(struct netdev_desc *desc)
|
|
|
|
{
|
|
|
|
return le64_to_cpu(desc->fraginfo) & DMA_BIT_MASK(48);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_list(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
struct sk_buff *skb;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Free all the skbuffs in the queue. */
|
|
|
|
for (i = 0; i < RX_RING_SIZE; i++) {
|
|
|
|
skb = np->rx_skbuff[i];
|
|
|
|
if (skb) {
|
|
|
|
pci_unmap_single(np->pdev, desc_to_dma(&np->rx_ring[i]),
|
|
|
|
skb->len, PCI_DMA_FROMDEVICE);
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
np->rx_skbuff[i] = NULL;
|
|
|
|
}
|
|
|
|
np->rx_ring[i].status = 0;
|
|
|
|
np->rx_ring[i].fraginfo = 0;
|
|
|
|
}
|
|
|
|
for (i = 0; i < TX_RING_SIZE; i++) {
|
|
|
|
skb = np->tx_skbuff[i];
|
|
|
|
if (skb) {
|
|
|
|
pci_unmap_single(np->pdev, desc_to_dma(&np->tx_ring[i]),
|
|
|
|
skb->len, PCI_DMA_TODEVICE);
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
np->tx_skbuff[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-20 02:13:06 +07:00
|
|
|
static void rio_reset_ring(struct netdev_private *np)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
np->cur_rx = 0;
|
|
|
|
np->cur_tx = 0;
|
|
|
|
np->old_rx = 0;
|
|
|
|
np->old_tx = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < TX_RING_SIZE; i++)
|
|
|
|
np->tx_ring[i].status = cpu_to_le64(TFDDone);
|
|
|
|
|
|
|
|
for (i = 0; i < RX_RING_SIZE; i++)
|
|
|
|
np->rx_ring[i].status = 0;
|
|
|
|
}
|
|
|
|
|
2015-11-20 02:13:04 +07:00
|
|
|
/* allocate and initialize Tx and Rx descriptors */
|
|
|
|
static int alloc_list(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
int i;
|
|
|
|
|
2015-11-20 02:13:06 +07:00
|
|
|
rio_reset_ring(np);
|
2015-11-20 02:13:04 +07:00
|
|
|
np->rx_buf_sz = (dev->mtu <= 1500 ? PACKET_SIZE : dev->mtu + 32);
|
|
|
|
|
|
|
|
/* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
|
|
|
|
for (i = 0; i < TX_RING_SIZE; i++) {
|
|
|
|
np->tx_skbuff[i] = NULL;
|
|
|
|
np->tx_ring[i].next_desc = cpu_to_le64(np->tx_ring_dma +
|
|
|
|
((i + 1) % TX_RING_SIZE) *
|
|
|
|
sizeof(struct netdev_desc));
|
|
|
|
}
|
|
|
|
|
2015-11-20 02:13:06 +07:00
|
|
|
/* Initialize Rx descriptors & allocate buffers */
|
2015-11-20 02:13:04 +07:00
|
|
|
for (i = 0; i < RX_RING_SIZE; i++) {
|
|
|
|
/* Allocated fixed size of skbuff */
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
|
|
|
|
np->rx_skbuff[i] = skb;
|
|
|
|
if (!skb) {
|
|
|
|
free_list(dev);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2015-11-20 02:13:06 +07:00
|
|
|
np->rx_ring[i].next_desc = cpu_to_le64(np->rx_ring_dma +
|
|
|
|
((i + 1) % RX_RING_SIZE) *
|
|
|
|
sizeof(struct netdev_desc));
|
2015-11-20 02:13:04 +07:00
|
|
|
/* Rubicon now supports 40 bits of addressing space. */
|
|
|
|
np->rx_ring[i].fraginfo =
|
|
|
|
cpu_to_le64(pci_map_single(
|
|
|
|
np->pdev, skb->data, np->rx_buf_sz,
|
|
|
|
PCI_DMA_FROMDEVICE));
|
|
|
|
np->rx_ring[i].fraginfo |= cpu_to_le64((u64)np->rx_buf_sz << 48);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-20 02:13:05 +07:00
|
|
|
static void rio_hw_init(struct net_device *dev)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2012-03-10 00:09:35 +07:00
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
int i;
|
|
|
|
u16 macctrl;
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Reset all logic functions */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(ASICCtrl + 2,
|
|
|
|
GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay(10);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2015-11-16 04:36:11 +07:00
|
|
|
rio_set_led_mode(dev);
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* DebugCtrl bit 4, 5, 9 must set */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(DebugCtrl, dr32(DebugCtrl) | 0x0230);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2015-11-20 02:13:05 +07:00
|
|
|
if (np->chip_id == CHIP_IP1000A &&
|
|
|
|
(np->pdev->revision == 0x40 || np->pdev->revision == 0x41)) {
|
|
|
|
/* PHY magic taken from ipg driver, undocumented registers */
|
|
|
|
mii_write(dev, np->phy_addr, 31, 0x0001);
|
|
|
|
mii_write(dev, np->phy_addr, 27, 0x01e0);
|
|
|
|
mii_write(dev, np->phy_addr, 31, 0x0002);
|
|
|
|
mii_write(dev, np->phy_addr, 27, 0xeb8e);
|
|
|
|
mii_write(dev, np->phy_addr, 31, 0x0000);
|
|
|
|
mii_write(dev, np->phy_addr, 30, 0x005e);
|
|
|
|
/* advertise 1000BASE-T half & full duplex, prefer MASTER */
|
|
|
|
mii_write(dev, np->phy_addr, MII_CTRL1000, 0x0700);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (np->phy_media)
|
|
|
|
mii_set_media_pcs(dev);
|
|
|
|
else
|
|
|
|
mii_set_media(dev);
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Jumbo frame */
|
|
|
|
if (np->jumbo != 0)
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(MaxFrameSize, MAX_JUMBO+14);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2015-11-20 02:13:04 +07:00
|
|
|
/* Set RFDListPtr */
|
|
|
|
dw32(RFDListPtr0, np->rx_ring_dma);
|
|
|
|
dw32(RFDListPtr1, 0);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2015-11-16 04:36:11 +07:00
|
|
|
/* Set station address */
|
|
|
|
/* 16 or 32-bit access is required by TC9020 datasheet but 8-bit works
|
|
|
|
* too. However, it doesn't work on IP1000A so we use 16-bit access.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
dw16(StationAddr0 + 2 * i,
|
|
|
|
cpu_to_le16(((u16 *)dev->dev_addr)[i]));
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
set_multicast (dev);
|
|
|
|
if (np->coalesce) {
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(RxDMAIntCtrl, np->rx_coalesce | np->rx_timeout << 16);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
/* Set RIO to poll every N*320nsec. */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw8(RxDMAPollPeriod, 0x20);
|
|
|
|
dw8(TxDMAPollPeriod, 0xff);
|
|
|
|
dw8(RxDMABurstThresh, 0x30);
|
|
|
|
dw8(RxDMAUrgentThresh, 0x30);
|
|
|
|
dw32(RmonStatMask, 0x0007ffff);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* clear statistics */
|
|
|
|
clear_stats (dev);
|
|
|
|
|
|
|
|
/* VLAN supported */
|
|
|
|
if (np->vlan) {
|
|
|
|
/* priority field in RxDMAIntCtrl */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(RxDMAIntCtrl, dr32(RxDMAIntCtrl) | 0x7 << 10);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* VLANId */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(VLANId, np->vlan);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Length/Type should be 0x8100 */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(VLANTag, 0x8100 << 16 | np->vlan);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Enable AutoVLANuntagging, but disable AutoVLANtagging.
|
|
|
|
VLAN information tagged by TFC' VID, CFI fields. */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(MACCtrl, dr32(MACCtrl) | AutoVLANuntagging);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Start Tx/Rx */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(MACCtrl, dr32(MACCtrl) | StatsEnable | RxEnable | TxEnable);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
macctrl = 0;
|
|
|
|
macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
|
|
|
|
macctrl |= (np->full_duplex) ? DuplexSelect : 0;
|
|
|
|
macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
|
|
|
|
macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(MACCtrl, macctrl);
|
2015-11-20 02:13:05 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void rio_hw_stop(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
|
|
|
|
|
|
|
/* Disable interrupts */
|
|
|
|
dw16(IntEnable, 0);
|
|
|
|
|
|
|
|
/* Stop Tx and Rx logics */
|
|
|
|
dw32(MACCtrl, TxDisable | RxDisable | StatsDisable);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rio_open(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
const int irq = np->pdev->irq;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
i = alloc_list(dev);
|
|
|
|
if (i)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
rio_hw_init(dev);
|
|
|
|
|
|
|
|
i = request_irq(irq, rio_interrupt, IRQF_SHARED, dev->name, dev);
|
|
|
|
if (i) {
|
|
|
|
rio_hw_stop(dev);
|
|
|
|
free_list(dev);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2017-10-17 07:29:11 +07:00
|
|
|
timer_setup(&np->timer, rio_timer, 0);
|
2015-11-20 02:13:05 +07:00
|
|
|
np->timer.expires = jiffies + 1 * HZ;
|
|
|
|
add_timer(&np->timer);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
netif_start_queue (dev);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
dl2k_enable_int(np);
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-09-14 00:24:59 +07:00
|
|
|
static void
|
2017-10-17 07:29:11 +07:00
|
|
|
rio_timer (struct timer_list *t)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2017-10-17 07:29:11 +07:00
|
|
|
struct netdev_private *np = from_timer(np, t, timer);
|
|
|
|
struct net_device *dev = pci_get_drvdata(np->pdev);
|
2005-04-17 05:20:36 +07:00
|
|
|
unsigned int entry;
|
|
|
|
int next_tick = 1*HZ;
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&np->rx_lock, flags);
|
|
|
|
/* Recover rx ring exhausted error */
|
|
|
|
if (np->cur_rx - np->old_rx >= RX_RING_SIZE) {
|
|
|
|
printk(KERN_INFO "Try to recover rx ring exhausted...\n");
|
|
|
|
/* Re-allocate skbuffs to fill the descriptor ring */
|
|
|
|
for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
|
|
|
|
struct sk_buff *skb;
|
|
|
|
entry = np->old_rx % RX_RING_SIZE;
|
|
|
|
/* Dropped packets don't need to re-allocate */
|
|
|
|
if (np->rx_skbuff[entry] == NULL) {
|
2009-10-13 12:34:20 +07:00
|
|
|
skb = netdev_alloc_skb_ip_align(dev,
|
|
|
|
np->rx_buf_sz);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (skb == NULL) {
|
|
|
|
np->rx_ring[entry].fraginfo = 0;
|
|
|
|
printk (KERN_INFO
|
|
|
|
"%s: Still unable to re-allocate Rx skbuff.#%d\n",
|
|
|
|
dev->name, entry);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
np->rx_skbuff[entry] = skb;
|
|
|
|
np->rx_ring[entry].fraginfo =
|
|
|
|
cpu_to_le64 (pci_map_single
|
2005-06-29 05:25:31 +07:00
|
|
|
(np->pdev, skb->data, np->rx_buf_sz,
|
2005-04-17 05:20:36 +07:00
|
|
|
PCI_DMA_FROMDEVICE));
|
|
|
|
}
|
|
|
|
np->rx_ring[entry].fraginfo |=
|
2007-12-23 01:11:18 +07:00
|
|
|
cpu_to_le64((u64)np->rx_buf_sz << 48);
|
2005-04-17 05:20:36 +07:00
|
|
|
np->rx_ring[entry].status = 0;
|
|
|
|
} /* end for */
|
|
|
|
} /* end if */
|
|
|
|
spin_unlock_irqrestore (&np->rx_lock, flags);
|
|
|
|
np->timer.expires = jiffies + next_tick;
|
|
|
|
add_timer(&np->timer);
|
|
|
|
}
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static void
|
netdev: pass the stuck queue to the timeout handler
This allows incrementing the correct timeout statistic without any mess.
Down the road, devices can learn to reset just the specific queue.
The patch was generated with the following script:
use strict;
use warnings;
our $^I = '.bak';
my @work = (
["arch/m68k/emu/nfeth.c", "nfeth_tx_timeout"],
["arch/um/drivers/net_kern.c", "uml_net_tx_timeout"],
["arch/um/drivers/vector_kern.c", "vector_net_tx_timeout"],
["arch/xtensa/platforms/iss/network.c", "iss_net_tx_timeout"],
["drivers/char/pcmcia/synclink_cs.c", "hdlcdev_tx_timeout"],
["drivers/infiniband/ulp/ipoib/ipoib_main.c", "ipoib_timeout"],
["drivers/infiniband/ulp/ipoib/ipoib_main.c", "ipoib_timeout"],
["drivers/message/fusion/mptlan.c", "mpt_lan_tx_timeout"],
["drivers/misc/sgi-xp/xpnet.c", "xpnet_dev_tx_timeout"],
["drivers/net/appletalk/cops.c", "cops_timeout"],
["drivers/net/arcnet/arcdevice.h", "arcnet_timeout"],
["drivers/net/arcnet/arcnet.c", "arcnet_timeout"],
["drivers/net/arcnet/com20020.c", "arcnet_timeout"],
["drivers/net/ethernet/3com/3c509.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c515.c", "corkscrew_timeout"],
["drivers/net/ethernet/3com/3c574_cs.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c589_cs.c", "el3_tx_timeout"],
["drivers/net/ethernet/3com/3c59x.c", "vortex_tx_timeout"],
["drivers/net/ethernet/3com/3c59x.c", "vortex_tx_timeout"],
["drivers/net/ethernet/3com/typhoon.c", "typhoon_tx_timeout"],
["drivers/net/ethernet/8390/8390.h", "ei_tx_timeout"],
["drivers/net/ethernet/8390/8390.h", "eip_tx_timeout"],
["drivers/net/ethernet/8390/8390.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/8390p.c", "eip_tx_timeout"],
["drivers/net/ethernet/8390/ax88796.c", "ax_ei_tx_timeout"],
["drivers/net/ethernet/8390/axnet_cs.c", "axnet_tx_timeout"],
["drivers/net/ethernet/8390/etherh.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/hydra.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/mac8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/mcf8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/lib8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/8390/ne2k-pci.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/pcnet_cs.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/smc-ultra.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/wd.c", "ei_tx_timeout"],
["drivers/net/ethernet/8390/zorro8390.c", "__ei_tx_timeout"],
["drivers/net/ethernet/adaptec/starfire.c", "tx_timeout"],
["drivers/net/ethernet/agere/et131x.c", "et131x_tx_timeout"],
["drivers/net/ethernet/allwinner/sun4i-emac.c", "emac_timeout"],
["drivers/net/ethernet/alteon/acenic.c", "ace_watchdog"],
["drivers/net/ethernet/amazon/ena/ena_netdev.c", "ena_tx_timeout"],
["drivers/net/ethernet/amd/7990.h", "lance_tx_timeout"],
["drivers/net/ethernet/amd/7990.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/a2065.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/am79c961a.c", "am79c961_timeout"],
["drivers/net/ethernet/amd/amd8111e.c", "amd8111e_tx_timeout"],
["drivers/net/ethernet/amd/ariadne.c", "ariadne_tx_timeout"],
["drivers/net/ethernet/amd/atarilance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/au1000_eth.c", "au1000_tx_timeout"],
["drivers/net/ethernet/amd/declance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/lance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/mvme147.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/ni65.c", "ni65_timeout"],
["drivers/net/ethernet/amd/nmclan_cs.c", "mace_tx_timeout"],
["drivers/net/ethernet/amd/pcnet32.c", "pcnet32_tx_timeout"],
["drivers/net/ethernet/amd/sunlance.c", "lance_tx_timeout"],
["drivers/net/ethernet/amd/xgbe/xgbe-drv.c", "xgbe_tx_timeout"],
["drivers/net/ethernet/apm/xgene-v2/main.c", "xge_timeout"],
["drivers/net/ethernet/apm/xgene/xgene_enet_main.c", "xgene_enet_timeout"],
["drivers/net/ethernet/apple/macmace.c", "mace_tx_timeout"],
["drivers/net/ethernet/atheros/ag71xx.c", "ag71xx_tx_timeout"],
["drivers/net/ethernet/atheros/alx/main.c", "alx_tx_timeout"],
["drivers/net/ethernet/atheros/atl1c/atl1c_main.c", "atl1c_tx_timeout"],
["drivers/net/ethernet/atheros/atl1e/atl1e_main.c", "atl1e_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl.c", "atlx_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl1.c", "atlx_tx_timeout"],
["drivers/net/ethernet/atheros/atlx/atl2.c", "atl2_tx_timeout"],
["drivers/net/ethernet/broadcom/b44.c", "b44_tx_timeout"],
["drivers/net/ethernet/broadcom/bcmsysport.c", "bcm_sysport_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2.c", "bnx2_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c", "bnx2x_tx_timeout"],
["drivers/net/ethernet/broadcom/bnxt/bnxt.c", "bnxt_tx_timeout"],
["drivers/net/ethernet/broadcom/genet/bcmgenet.c", "bcmgenet_timeout"],
["drivers/net/ethernet/broadcom/sb1250-mac.c", "sbmac_tx_timeout"],
["drivers/net/ethernet/broadcom/tg3.c", "tg3_tx_timeout"],
["drivers/net/ethernet/calxeda/xgmac.c", "xgmac_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_main.c", "liquidio_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_vf_main.c", "liquidio_tx_timeout"],
["drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c", "lio_vf_rep_tx_timeout"],
["drivers/net/ethernet/cavium/thunder/nicvf_main.c", "nicvf_tx_timeout"],
["drivers/net/ethernet/cirrus/cs89x0.c", "net_timeout"],
["drivers/net/ethernet/cisco/enic/enic_main.c", "enic_tx_timeout"],
["drivers/net/ethernet/cisco/enic/enic_main.c", "enic_tx_timeout"],
["drivers/net/ethernet/cortina/gemini.c", "gmac_tx_timeout"],
["drivers/net/ethernet/davicom/dm9000.c", "dm9000_timeout"],
["drivers/net/ethernet/dec/tulip/de2104x.c", "de_tx_timeout"],
["drivers/net/ethernet/dec/tulip/tulip_core.c", "tulip_tx_timeout"],
["drivers/net/ethernet/dec/tulip/winbond-840.c", "tx_timeout"],
["drivers/net/ethernet/dlink/dl2k.c", "rio_tx_timeout"],
["drivers/net/ethernet/dlink/sundance.c", "tx_timeout"],
["drivers/net/ethernet/emulex/benet/be_main.c", "be_tx_timeout"],
["drivers/net/ethernet/ethoc.c", "ethoc_tx_timeout"],
["drivers/net/ethernet/faraday/ftgmac100.c", "ftgmac100_tx_timeout"],
["drivers/net/ethernet/fealnx.c", "fealnx_tx_timeout"],
["drivers/net/ethernet/freescale/dpaa/dpaa_eth.c", "dpaa_tx_timeout"],
["drivers/net/ethernet/freescale/fec_main.c", "fec_timeout"],
["drivers/net/ethernet/freescale/fec_mpc52xx.c", "mpc52xx_fec_tx_timeout"],
["drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c", "fs_timeout"],
["drivers/net/ethernet/freescale/gianfar.c", "gfar_timeout"],
["drivers/net/ethernet/freescale/ucc_geth.c", "ucc_geth_timeout"],
["drivers/net/ethernet/fujitsu/fmvj18x_cs.c", "fjn_tx_timeout"],
["drivers/net/ethernet/google/gve/gve_main.c", "gve_tx_timeout"],
["drivers/net/ethernet/hisilicon/hip04_eth.c", "hip04_timeout"],
["drivers/net/ethernet/hisilicon/hix5hd2_gmac.c", "hix5hd2_net_timeout"],
["drivers/net/ethernet/hisilicon/hns/hns_enet.c", "hns_nic_net_timeout"],
["drivers/net/ethernet/hisilicon/hns3/hns3_enet.c", "hns3_nic_net_timeout"],
["drivers/net/ethernet/huawei/hinic/hinic_main.c", "hinic_tx_timeout"],
["drivers/net/ethernet/i825xx/82596.c", "i596_tx_timeout"],
["drivers/net/ethernet/i825xx/ether1.c", "ether1_timeout"],
["drivers/net/ethernet/i825xx/lib82596.c", "i596_tx_timeout"],
["drivers/net/ethernet/i825xx/sun3_82586.c", "sun3_82586_timeout"],
["drivers/net/ethernet/ibm/ehea/ehea_main.c", "ehea_tx_watchdog"],
["drivers/net/ethernet/ibm/emac/core.c", "emac_tx_timeout"],
["drivers/net/ethernet/ibm/emac/core.c", "emac_tx_timeout"],
["drivers/net/ethernet/ibm/ibmvnic.c", "ibmvnic_tx_timeout"],
["drivers/net/ethernet/intel/e100.c", "e100_tx_timeout"],
["drivers/net/ethernet/intel/e1000/e1000_main.c", "e1000_tx_timeout"],
["drivers/net/ethernet/intel/e1000e/netdev.c", "e1000_tx_timeout"],
["drivers/net/ethernet/intel/fm10k/fm10k_netdev.c", "fm10k_tx_timeout"],
["drivers/net/ethernet/intel/i40e/i40e_main.c", "i40e_tx_timeout"],
["drivers/net/ethernet/intel/iavf/iavf_main.c", "iavf_tx_timeout"],
["drivers/net/ethernet/intel/ice/ice_main.c", "ice_tx_timeout"],
["drivers/net/ethernet/intel/ice/ice_main.c", "ice_tx_timeout"],
["drivers/net/ethernet/intel/igb/igb_main.c", "igb_tx_timeout"],
["drivers/net/ethernet/intel/igbvf/netdev.c", "igbvf_tx_timeout"],
["drivers/net/ethernet/intel/ixgb/ixgb_main.c", "ixgb_tx_timeout"],
["drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c", "adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev);"],
["drivers/net/ethernet/intel/ixgbe/ixgbe_main.c", "ixgbe_tx_timeout"],
["drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c", "ixgbevf_tx_timeout"],
["drivers/net/ethernet/jme.c", "jme_tx_timeout"],
["drivers/net/ethernet/korina.c", "korina_tx_timeout"],
["drivers/net/ethernet/lantiq_etop.c", "ltq_etop_tx_timeout"],
["drivers/net/ethernet/marvell/mv643xx_eth.c", "mv643xx_eth_tx_timeout"],
["drivers/net/ethernet/marvell/pxa168_eth.c", "pxa168_eth_tx_timeout"],
["drivers/net/ethernet/marvell/skge.c", "skge_tx_timeout"],
["drivers/net/ethernet/marvell/sky2.c", "sky2_tx_timeout"],
["drivers/net/ethernet/marvell/sky2.c", "sky2_tx_timeout"],
["drivers/net/ethernet/mediatek/mtk_eth_soc.c", "mtk_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx4/en_netdev.c", "mlx4_en_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx4/en_netdev.c", "mlx4_en_tx_timeout"],
["drivers/net/ethernet/mellanox/mlx5/core/en_main.c", "mlx5e_tx_timeout"],
["drivers/net/ethernet/micrel/ks8842.c", "ks8842_tx_timeout"],
["drivers/net/ethernet/micrel/ksz884x.c", "netdev_tx_timeout"],
["drivers/net/ethernet/microchip/enc28j60.c", "enc28j60_tx_timeout"],
["drivers/net/ethernet/microchip/encx24j600.c", "encx24j600_tx_timeout"],
["drivers/net/ethernet/natsemi/sonic.h", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/sonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/jazzsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/macsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/natsemi/natsemi.c", "ns_tx_timeout"],
["drivers/net/ethernet/natsemi/ns83820.c", "ns83820_tx_timeout"],
["drivers/net/ethernet/natsemi/xtsonic.c", "sonic_tx_timeout"],
["drivers/net/ethernet/neterion/s2io.h", "s2io_tx_watchdog"],
["drivers/net/ethernet/neterion/s2io.c", "s2io_tx_watchdog"],
["drivers/net/ethernet/neterion/vxge/vxge-main.c", "vxge_tx_watchdog"],
["drivers/net/ethernet/netronome/nfp/nfp_net_common.c", "nfp_net_tx_timeout"],
["drivers/net/ethernet/nvidia/forcedeth.c", "nv_tx_timeout"],
["drivers/net/ethernet/nvidia/forcedeth.c", "nv_tx_timeout"],
["drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c", "pch_gbe_tx_timeout"],
["drivers/net/ethernet/packetengines/hamachi.c", "hamachi_tx_timeout"],
["drivers/net/ethernet/packetengines/yellowfin.c", "yellowfin_tx_timeout"],
["drivers/net/ethernet/pensando/ionic/ionic_lif.c", "ionic_tx_timeout"],
["drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c", "netxen_tx_timeout"],
["drivers/net/ethernet/qlogic/qla3xxx.c", "ql3xxx_tx_timeout"],
["drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c", "qlcnic_tx_timeout"],
["drivers/net/ethernet/qualcomm/emac/emac.c", "emac_tx_timeout"],
["drivers/net/ethernet/qualcomm/qca_spi.c", "qcaspi_netdev_tx_timeout"],
["drivers/net/ethernet/qualcomm/qca_uart.c", "qcauart_netdev_tx_timeout"],
["drivers/net/ethernet/rdc/r6040.c", "r6040_tx_timeout"],
["drivers/net/ethernet/realtek/8139cp.c", "cp_tx_timeout"],
["drivers/net/ethernet/realtek/8139too.c", "rtl8139_tx_timeout"],
["drivers/net/ethernet/realtek/atp.c", "tx_timeout"],
["drivers/net/ethernet/realtek/r8169_main.c", "rtl8169_tx_timeout"],
["drivers/net/ethernet/renesas/ravb_main.c", "ravb_tx_timeout"],
["drivers/net/ethernet/renesas/sh_eth.c", "sh_eth_tx_timeout"],
["drivers/net/ethernet/renesas/sh_eth.c", "sh_eth_tx_timeout"],
["drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c", "sxgbe_tx_timeout"],
["drivers/net/ethernet/seeq/ether3.c", "ether3_timeout"],
["drivers/net/ethernet/seeq/sgiseeq.c", "timeout"],
["drivers/net/ethernet/sfc/efx.c", "efx_watchdog"],
["drivers/net/ethernet/sfc/falcon/efx.c", "ef4_watchdog"],
["drivers/net/ethernet/sgi/ioc3-eth.c", "ioc3_timeout"],
["drivers/net/ethernet/sgi/meth.c", "meth_tx_timeout"],
["drivers/net/ethernet/silan/sc92031.c", "sc92031_tx_timeout"],
["drivers/net/ethernet/sis/sis190.c", "sis190_tx_timeout"],
["drivers/net/ethernet/sis/sis900.c", "sis900_tx_timeout"],
["drivers/net/ethernet/smsc/epic100.c", "epic_tx_timeout"],
["drivers/net/ethernet/smsc/smc911x.c", "smc911x_timeout"],
["drivers/net/ethernet/smsc/smc9194.c", "smc_timeout"],
["drivers/net/ethernet/smsc/smc91c92_cs.c", "smc_tx_timeout"],
["drivers/net/ethernet/smsc/smc91x.c", "smc_timeout"],
["drivers/net/ethernet/stmicro/stmmac/stmmac_main.c", "stmmac_tx_timeout"],
["drivers/net/ethernet/sun/cassini.c", "cas_tx_timeout"],
["drivers/net/ethernet/sun/ldmvsw.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/niu.c", "niu_tx_timeout"],
["drivers/net/ethernet/sun/sunbmac.c", "bigmac_tx_timeout"],
["drivers/net/ethernet/sun/sungem.c", "gem_tx_timeout"],
["drivers/net/ethernet/sun/sunhme.c", "happy_meal_tx_timeout"],
["drivers/net/ethernet/sun/sunqe.c", "qe_tx_timeout"],
["drivers/net/ethernet/sun/sunvnet.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/sunvnet_common.c", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/sun/sunvnet_common.h", "sunvnet_tx_timeout_common"],
["drivers/net/ethernet/synopsys/dwc-xlgmac-net.c", "xlgmac_tx_timeout"],
["drivers/net/ethernet/ti/cpmac.c", "cpmac_tx_timeout"],
["drivers/net/ethernet/ti/cpsw.c", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/cpsw_priv.c", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/cpsw_priv.h", "cpsw_ndo_tx_timeout"],
["drivers/net/ethernet/ti/davinci_emac.c", "emac_dev_tx_timeout"],
["drivers/net/ethernet/ti/netcp_core.c", "netcp_ndo_tx_timeout"],
["drivers/net/ethernet/ti/tlan.c", "tlan_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_net.h", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_net.c", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/ps3_gelic_wireless.c", "gelic_net_tx_timeout"],
["drivers/net/ethernet/toshiba/spider_net.c", "spider_net_tx_timeout"],
["drivers/net/ethernet/toshiba/tc35815.c", "tc35815_tx_timeout"],
["drivers/net/ethernet/via/via-rhine.c", "rhine_tx_timeout"],
["drivers/net/ethernet/wiznet/w5100.c", "w5100_tx_timeout"],
["drivers/net/ethernet/wiznet/w5300.c", "w5300_tx_timeout"],
["drivers/net/ethernet/xilinx/xilinx_emaclite.c", "xemaclite_tx_timeout"],
["drivers/net/ethernet/xircom/xirc2ps_cs.c", "xirc_tx_timeout"],
["drivers/net/fjes/fjes_main.c", "fjes_tx_retry"],
["drivers/net/slip/slip.c", "sl_tx_timeout"],
["include/linux/usb/usbnet.h", "usbnet_tx_timeout"],
["drivers/net/usb/aqc111.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/asix_devices.c", "usbnet_tx_timeout"],
["drivers/net/usb/ax88172a.c", "usbnet_tx_timeout"],
["drivers/net/usb/ax88179_178a.c", "usbnet_tx_timeout"],
["drivers/net/usb/catc.c", "catc_tx_timeout"],
["drivers/net/usb/cdc_mbim.c", "usbnet_tx_timeout"],
["drivers/net/usb/cdc_ncm.c", "usbnet_tx_timeout"],
["drivers/net/usb/dm9601.c", "usbnet_tx_timeout"],
["drivers/net/usb/hso.c", "hso_net_tx_timeout"],
["drivers/net/usb/int51x1.c", "usbnet_tx_timeout"],
["drivers/net/usb/ipheth.c", "ipheth_tx_timeout"],
["drivers/net/usb/kaweth.c", "kaweth_tx_timeout"],
["drivers/net/usb/lan78xx.c", "lan78xx_tx_timeout"],
["drivers/net/usb/mcs7830.c", "usbnet_tx_timeout"],
["drivers/net/usb/pegasus.c", "pegasus_tx_timeout"],
["drivers/net/usb/qmi_wwan.c", "usbnet_tx_timeout"],
["drivers/net/usb/r8152.c", "rtl8152_tx_timeout"],
["drivers/net/usb/rndis_host.c", "usbnet_tx_timeout"],
["drivers/net/usb/rtl8150.c", "rtl8150_tx_timeout"],
["drivers/net/usb/sierra_net.c", "usbnet_tx_timeout"],
["drivers/net/usb/smsc75xx.c", "usbnet_tx_timeout"],
["drivers/net/usb/smsc95xx.c", "usbnet_tx_timeout"],
["drivers/net/usb/sr9700.c", "usbnet_tx_timeout"],
["drivers/net/usb/sr9800.c", "usbnet_tx_timeout"],
["drivers/net/usb/usbnet.c", "usbnet_tx_timeout"],
["drivers/net/vmxnet3/vmxnet3_drv.c", "vmxnet3_tx_timeout"],
["drivers/net/wan/cosa.c", "cosa_net_timeout"],
["drivers/net/wan/farsync.c", "fst_tx_timeout"],
["drivers/net/wan/fsl_ucc_hdlc.c", "uhdlc_tx_timeout"],
["drivers/net/wan/lmc/lmc_main.c", "lmc_driver_timeout"],
["drivers/net/wan/x25_asy.c", "x25_asy_timeout"],
["drivers/net/wimax/i2400m/netdev.c", "i2400m_tx_timeout"],
["drivers/net/wireless/intel/ipw2x00/ipw2100.c", "ipw2100_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/hostap/hostap_main.c", "prism2_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/main.c", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/orinoco_usb.c", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/orinoco/orinoco.h", "orinoco_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_dev.c", "islpci_eth_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_eth.c", "islpci_eth_tx_timeout"],
["drivers/net/wireless/intersil/prism54/islpci_eth.h", "islpci_eth_tx_timeout"],
["drivers/net/wireless/marvell/mwifiex/main.c", "mwifiex_tx_timeout"],
["drivers/net/wireless/quantenna/qtnfmac/core.c", "qtnf_netdev_tx_timeout"],
["drivers/net/wireless/quantenna/qtnfmac/core.h", "qtnf_netdev_tx_timeout"],
["drivers/net/wireless/rndis_wlan.c", "usbnet_tx_timeout"],
["drivers/net/wireless/wl3501_cs.c", "wl3501_tx_timeout"],
["drivers/net/wireless/zydas/zd1201.c", "zd1201_tx_timeout"],
["drivers/s390/net/qeth_core.h", "qeth_tx_timeout"],
["drivers/s390/net/qeth_core_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l2_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l2_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l3_main.c", "qeth_tx_timeout"],
["drivers/s390/net/qeth_l3_main.c", "qeth_tx_timeout"],
["drivers/staging/ks7010/ks_wlan_net.c", "ks_wlan_tx_timeout"],
["drivers/staging/qlge/qlge_main.c", "qlge_tx_timeout"],
["drivers/staging/rtl8192e/rtl8192e/rtl_core.c", "_rtl92e_tx_timeout"],
["drivers/staging/rtl8192u/r8192U_core.c", "tx_timeout"],
["drivers/staging/unisys/visornic/visornic_main.c", "visornic_xmit_timeout"],
["drivers/staging/wlan-ng/p80211netdev.c", "p80211knetdev_tx_timeout"],
["drivers/tty/n_gsm.c", "gsm_mux_net_tx_timeout"],
["drivers/tty/synclink.c", "hdlcdev_tx_timeout"],
["drivers/tty/synclink_gt.c", "hdlcdev_tx_timeout"],
["drivers/tty/synclinkmp.c", "hdlcdev_tx_timeout"],
["net/atm/lec.c", "lec_tx_timeout"],
["net/bluetooth/bnep/netdev.c", "bnep_net_timeout"]
);
for my $p (@work) {
my @pair = @$p;
my $file = $pair[0];
my $func = $pair[1];
print STDERR $file , ": ", $func,"\n";
our @ARGV = ($file);
while (<ARGV>) {
if (m/($func\s*\(struct\s+net_device\s+\*[A-Za-z_]?[A-Za-z-0-9_]*)(\))/) {
print STDERR "found $1+$2 in $file\n";
}
if (s/($func\s*\(struct\s+net_device\s+\*[A-Za-z_]?[A-Za-z-0-9_]*)(\))/$1, unsigned int txqueue$2/) {
print STDERR "$func found in $file\n";
}
print;
}
}
where the list of files and functions is simply from:
git grep ndo_tx_timeout, with manual addition of headers
in the rare cases where the function is from a header,
then manually changing the few places which actually
call ndo_tx_timeout.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Heiner Kallweit <hkallweit1@gmail.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Shannon Nelson <snelson@pensando.io>
Reviewed-by: Martin Habets <mhabets@solarflare.com>
changes from v9:
fixup a forward declaration
changes from v9:
more leftovers from v3 change
changes from v8:
fix up a missing direct call to timeout
rebased on net-next
changes from v7:
fixup leftovers from v3 change
changes from v6:
fix typo in rtl driver
changes from v5:
add missing files (allow any net device argument name)
changes from v4:
add a missing driver header
changes from v3:
change queue # to unsigned
Changes from v2:
added headers
Changes from v1:
Fix errors found by kbuild:
generalize the pattern a bit, to pick up
a couple of instances missed by the previous
version.
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-12-10 21:23:51 +07:00
|
|
|
rio_tx_timeout (struct net_device *dev, unsigned int txqueue)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
printk (KERN_INFO "%s: Tx timed out (%4.4x), is buffer full?\n",
|
2012-03-10 00:09:35 +07:00
|
|
|
dev->name, dr32(TxStatus));
|
2005-04-17 05:20:36 +07:00
|
|
|
rio_free_tx(dev, 0);
|
|
|
|
dev->if_port = 0;
|
2016-05-03 21:33:13 +07:00
|
|
|
netif_trans_update(dev); /* prevent tx timeout */
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2009-09-01 02:50:58 +07:00
|
|
|
static netdev_tx_t
|
2005-04-17 05:20:36 +07:00
|
|
|
start_xmit (struct sk_buff *skb, struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2012-03-10 00:09:35 +07:00
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct netdev_desc *txdesc;
|
|
|
|
unsigned entry;
|
|
|
|
u64 tfc_vlan_tag = 0;
|
|
|
|
|
|
|
|
if (np->link_status == 0) { /* Link Down */
|
|
|
|
dev_kfree_skb(skb);
|
2009-05-28 07:00:41 +07:00
|
|
|
return NETDEV_TX_OK;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
entry = np->cur_tx % TX_RING_SIZE;
|
|
|
|
np->tx_skbuff[entry] = skb;
|
|
|
|
txdesc = &np->tx_ring[entry];
|
|
|
|
|
|
|
|
#if 0
|
2006-08-30 06:44:56 +07:00
|
|
|
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
2005-04-17 05:20:36 +07:00
|
|
|
txdesc->status |=
|
|
|
|
cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
|
|
|
|
IPChecksumEnable);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (np->vlan) {
|
2007-12-23 01:11:18 +07:00
|
|
|
tfc_vlan_tag = VLANTagInsert |
|
|
|
|
((u64)np->vlan << 32) |
|
|
|
|
((u64)skb->priority << 45);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
txdesc->fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data,
|
|
|
|
skb->len,
|
|
|
|
PCI_DMA_TODEVICE));
|
2007-12-23 01:11:18 +07:00
|
|
|
txdesc->fraginfo |= cpu_to_le64((u64)skb->len << 48);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* DL2K bug: DMA fails to get next descriptor ptr in 10Mbps mode
|
|
|
|
* Work around: Always use 1 descriptor in 10Mbps mode */
|
|
|
|
if (entry % np->tx_coalesce == 0 || np->speed == 10)
|
|
|
|
txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
|
2006-09-14 00:24:59 +07:00
|
|
|
WordAlignDisable |
|
2005-04-17 05:20:36 +07:00
|
|
|
TxDMAIndicate |
|
|
|
|
(1 << FragCountShift));
|
|
|
|
else
|
|
|
|
txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
|
2006-09-14 00:24:59 +07:00
|
|
|
WordAlignDisable |
|
2005-04-17 05:20:36 +07:00
|
|
|
(1 << FragCountShift));
|
|
|
|
|
|
|
|
/* TxDMAPollNow */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(DMACtrl, dr32(DMACtrl) | 0x00001000);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Schedule ISR */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(CountDown, 10000);
|
2005-04-17 05:20:36 +07:00
|
|
|
np->cur_tx = (np->cur_tx + 1) % TX_RING_SIZE;
|
|
|
|
if ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
|
|
|
|
< TX_QUEUE_LEN - 1 && np->speed != 10) {
|
|
|
|
/* do nothing */
|
|
|
|
} else if (!netif_queue_stopped(dev)) {
|
|
|
|
netif_stop_queue (dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The first TFDListPtr */
|
2012-03-10 00:09:35 +07:00
|
|
|
if (!dr32(TFDListPtr0)) {
|
|
|
|
dw32(TFDListPtr0, np->tx_ring_dma +
|
|
|
|
entry * sizeof (struct netdev_desc));
|
|
|
|
dw32(TFDListPtr1, 0);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2009-05-28 07:00:41 +07:00
|
|
|
return NETDEV_TX_OK;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static irqreturn_t
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
|
|
|
rio_interrupt (int irq, void *dev_instance)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct net_device *dev = dev_instance;
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
unsigned int_status;
|
|
|
|
int cnt = max_intrloop;
|
|
|
|
int handled = 0;
|
|
|
|
|
|
|
|
while (1) {
|
2012-03-10 00:09:35 +07:00
|
|
|
int_status = dr16(IntStatus);
|
|
|
|
dw16(IntStatus, int_status);
|
2005-04-17 05:20:36 +07:00
|
|
|
int_status &= DEFAULT_INTR;
|
|
|
|
if (int_status == 0 || --cnt < 0)
|
|
|
|
break;
|
|
|
|
handled = 1;
|
|
|
|
/* Processing received packets */
|
|
|
|
if (int_status & RxDMAComplete)
|
|
|
|
receive_packet (dev);
|
|
|
|
/* TxDMAComplete interrupt */
|
|
|
|
if ((int_status & (TxDMAComplete|IntRequested))) {
|
|
|
|
int tx_status;
|
2012-03-10 00:09:35 +07:00
|
|
|
tx_status = dr32(TxStatus);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (tx_status & 0x01)
|
|
|
|
tx_error (dev, tx_status);
|
|
|
|
/* Free used tx skbuffs */
|
2006-09-14 00:24:59 +07:00
|
|
|
rio_free_tx (dev, 1);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle uncommon events */
|
|
|
|
if (int_status &
|
|
|
|
(HostError | LinkEvent | UpdateStats))
|
|
|
|
rio_error (dev, int_status);
|
|
|
|
}
|
|
|
|
if (np->cur_tx != np->old_tx)
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(CountDown, 100);
|
2005-04-17 05:20:36 +07:00
|
|
|
return IRQ_RETVAL(handled);
|
|
|
|
}
|
|
|
|
|
2006-09-14 00:24:59 +07:00
|
|
|
static void
|
|
|
|
rio_free_tx (struct net_device *dev, int irq)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
int entry = np->old_tx % TX_RING_SIZE;
|
|
|
|
int tx_use = 0;
|
|
|
|
unsigned long flag = 0;
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
if (irq)
|
|
|
|
spin_lock(&np->tx_lock);
|
|
|
|
else
|
|
|
|
spin_lock_irqsave(&np->tx_lock, flag);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Free used tx skbuffs */
|
|
|
|
while (entry != np->cur_tx) {
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
2007-12-23 01:11:18 +07:00
|
|
|
if (!(np->tx_ring[entry].status & cpu_to_le64(TFDDone)))
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
skb = np->tx_skbuff[entry];
|
|
|
|
pci_unmap_single (np->pdev,
|
2007-12-23 01:11:18 +07:00
|
|
|
desc_to_dma(&np->tx_ring[entry]),
|
2005-04-17 05:20:36 +07:00
|
|
|
skb->len, PCI_DMA_TODEVICE);
|
|
|
|
if (irq)
|
2019-02-14 13:40:56 +07:00
|
|
|
dev_consume_skb_irq(skb);
|
2005-04-17 05:20:36 +07:00
|
|
|
else
|
2019-02-14 13:40:31 +07:00
|
|
|
dev_kfree_skb(skb);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
np->tx_skbuff[entry] = NULL;
|
|
|
|
entry = (entry + 1) % TX_RING_SIZE;
|
|
|
|
tx_use++;
|
|
|
|
}
|
|
|
|
if (irq)
|
|
|
|
spin_unlock(&np->tx_lock);
|
|
|
|
else
|
|
|
|
spin_unlock_irqrestore(&np->tx_lock, flag);
|
|
|
|
np->old_tx = entry;
|
|
|
|
|
2006-09-14 00:24:59 +07:00
|
|
|
/* If the ring is no longer full, clear tx_full and
|
2005-04-17 05:20:36 +07:00
|
|
|
call netif_wake_queue() */
|
|
|
|
|
|
|
|
if (netif_queue_stopped(dev) &&
|
2006-09-14 00:24:59 +07:00
|
|
|
((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
|
2005-04-17 05:20:36 +07:00
|
|
|
< TX_QUEUE_LEN - 1 || np->speed == 10)) {
|
|
|
|
netif_wake_queue (dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
tx_error (struct net_device *dev, int tx_status)
|
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
int frame_id;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
frame_id = (tx_status & 0xffff0000);
|
|
|
|
printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
|
|
|
|
dev->name, tx_status, frame_id);
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.tx_errors++;
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Ttransmit Underrun */
|
|
|
|
if (tx_status & 0x10) {
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.tx_fifo_errors++;
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(TxStartThresh, dr16(TxStartThresh) + 0x10);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Transmit Underrun need to set TxReset, DMARest, FIFOReset */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(ASICCtrl + 2,
|
|
|
|
TxReset | DMAReset | FIFOReset | NetworkReset);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Wait for ResetBusy bit clear */
|
|
|
|
for (i = 50; i > 0; i--) {
|
2012-03-10 00:09:35 +07:00
|
|
|
if (!(dr16(ASICCtrl + 2) & ResetBusy))
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
mdelay (1);
|
|
|
|
}
|
2015-11-16 04:36:11 +07:00
|
|
|
rio_set_led_mode(dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
rio_free_tx (dev, 1);
|
|
|
|
/* Reset TFDListPtr */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(TFDListPtr0, np->tx_ring_dma +
|
|
|
|
np->old_tx * sizeof (struct netdev_desc));
|
|
|
|
dw32(TFDListPtr1, 0);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Let TxStartThresh stay default value */
|
|
|
|
}
|
|
|
|
/* Late Collision */
|
|
|
|
if (tx_status & 0x04) {
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.tx_fifo_errors++;
|
2005-04-17 05:20:36 +07:00
|
|
|
/* TxReset and clear FIFO */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(ASICCtrl + 2, TxReset | FIFOReset);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Wait reset done */
|
|
|
|
for (i = 50; i > 0; i--) {
|
2012-03-10 00:09:35 +07:00
|
|
|
if (!(dr16(ASICCtrl + 2) & ResetBusy))
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
mdelay (1);
|
|
|
|
}
|
2015-11-16 04:36:11 +07:00
|
|
|
rio_set_led_mode(dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Let TxStartThresh stay default value */
|
|
|
|
}
|
|
|
|
/* Maximum Collisions */
|
2006-09-14 00:24:59 +07:00
|
|
|
if (tx_status & 0x08)
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.collisions++;
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Restart the Tx */
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(MACCtrl, dr16(MACCtrl) | TxEnable);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
receive_packet (struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
int entry = np->cur_rx % RX_RING_SIZE;
|
|
|
|
int cnt = 30;
|
|
|
|
|
|
|
|
/* If RFDDone, FrameStart and FrameEnd set, there is a new packet in. */
|
|
|
|
while (1) {
|
|
|
|
struct netdev_desc *desc = &np->rx_ring[entry];
|
|
|
|
int pkt_len;
|
|
|
|
u64 frame_status;
|
|
|
|
|
2007-12-23 01:11:18 +07:00
|
|
|
if (!(desc->status & cpu_to_le64(RFDDone)) ||
|
|
|
|
!(desc->status & cpu_to_le64(FrameStart)) ||
|
|
|
|
!(desc->status & cpu_to_le64(FrameEnd)))
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Chip omits the CRC. */
|
2007-12-23 01:11:18 +07:00
|
|
|
frame_status = le64_to_cpu(desc->status);
|
|
|
|
pkt_len = frame_status & 0xffff;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (--cnt < 0)
|
|
|
|
break;
|
|
|
|
/* Update rx error statistics, drop packet. */
|
|
|
|
if (frame_status & RFS_Errors) {
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.rx_errors++;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (frame_status & (RxRuntFrame | RxLengthError))
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.rx_length_errors++;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (frame_status & RxFCSError)
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.rx_crc_errors++;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (frame_status & RxAlignmentError && np->speed != 1000)
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.rx_frame_errors++;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (frame_status & RxFIFOOverrun)
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.rx_fifo_errors++;
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
/* Small skbuffs for short packets */
|
|
|
|
if (pkt_len > copy_thresh) {
|
2006-03-11 04:12:10 +07:00
|
|
|
pci_unmap_single (np->pdev,
|
2007-12-23 01:11:18 +07:00
|
|
|
desc_to_dma(desc),
|
2005-04-17 05:20:36 +07:00
|
|
|
np->rx_buf_sz,
|
|
|
|
PCI_DMA_FROMDEVICE);
|
|
|
|
skb_put (skb = np->rx_skbuff[entry], pkt_len);
|
|
|
|
np->rx_skbuff[entry] = NULL;
|
2009-10-13 12:34:20 +07:00
|
|
|
} else if ((skb = netdev_alloc_skb_ip_align(dev, pkt_len))) {
|
2005-04-17 05:20:36 +07:00
|
|
|
pci_dma_sync_single_for_cpu(np->pdev,
|
2007-12-23 01:11:18 +07:00
|
|
|
desc_to_dma(desc),
|
2005-04-17 05:20:36 +07:00
|
|
|
np->rx_buf_sz,
|
|
|
|
PCI_DMA_FROMDEVICE);
|
2007-07-11 12:08:12 +07:00
|
|
|
skb_copy_to_linear_data (skb,
|
2005-06-29 05:25:31 +07:00
|
|
|
np->rx_skbuff[entry]->data,
|
2007-07-11 12:08:12 +07:00
|
|
|
pkt_len);
|
2005-04-17 05:20:36 +07:00
|
|
|
skb_put (skb, pkt_len);
|
|
|
|
pci_dma_sync_single_for_device(np->pdev,
|
2007-12-23 01:11:18 +07:00
|
|
|
desc_to_dma(desc),
|
2005-04-17 05:20:36 +07:00
|
|
|
np->rx_buf_sz,
|
|
|
|
PCI_DMA_FROMDEVICE);
|
|
|
|
}
|
|
|
|
skb->protocol = eth_type_trans (skb, dev);
|
2006-09-14 00:24:59 +07:00
|
|
|
#if 0
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Checksum done by hw, but csum value unavailable. */
|
2007-06-09 05:46:36 +07:00
|
|
|
if (np->pdev->pci_rev_id >= 0x0c &&
|
2005-04-17 05:20:36 +07:00
|
|
|
!(frame_status & (TCPError | UDPError | IPError))) {
|
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
2006-09-14 00:24:59 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
|
|
|
netif_rx (skb);
|
|
|
|
}
|
|
|
|
entry = (entry + 1) % RX_RING_SIZE;
|
|
|
|
}
|
|
|
|
spin_lock(&np->rx_lock);
|
|
|
|
np->cur_rx = entry;
|
|
|
|
/* Re-allocate skbuffs to fill the descriptor ring */
|
|
|
|
entry = np->old_rx;
|
|
|
|
while (entry != np->cur_rx) {
|
|
|
|
struct sk_buff *skb;
|
|
|
|
/* Dropped packets don't need to re-allocate */
|
|
|
|
if (np->rx_skbuff[entry] == NULL) {
|
2009-10-13 12:34:20 +07:00
|
|
|
skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (skb == NULL) {
|
|
|
|
np->rx_ring[entry].fraginfo = 0;
|
|
|
|
printk (KERN_INFO
|
|
|
|
"%s: receive_packet: "
|
|
|
|
"Unable to re-allocate Rx skbuff.#%d\n",
|
|
|
|
dev->name, entry);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
np->rx_skbuff[entry] = skb;
|
|
|
|
np->rx_ring[entry].fraginfo =
|
|
|
|
cpu_to_le64 (pci_map_single
|
2005-06-29 05:25:31 +07:00
|
|
|
(np->pdev, skb->data, np->rx_buf_sz,
|
2005-04-17 05:20:36 +07:00
|
|
|
PCI_DMA_FROMDEVICE));
|
|
|
|
}
|
|
|
|
np->rx_ring[entry].fraginfo |=
|
2007-12-23 01:11:18 +07:00
|
|
|
cpu_to_le64((u64)np->rx_buf_sz << 48);
|
2005-04-17 05:20:36 +07:00
|
|
|
np->rx_ring[entry].status = 0;
|
|
|
|
entry = (entry + 1) % RX_RING_SIZE;
|
|
|
|
}
|
|
|
|
np->old_rx = entry;
|
|
|
|
spin_unlock(&np->rx_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rio_error (struct net_device *dev, int int_status)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2012-03-10 00:09:35 +07:00
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
u16 macctrl;
|
|
|
|
|
|
|
|
/* Link change event */
|
|
|
|
if (int_status & LinkEvent) {
|
|
|
|
if (mii_wait_link (dev, 10) == 0) {
|
|
|
|
printk (KERN_INFO "%s: Link up\n", dev->name);
|
|
|
|
if (np->phy_media)
|
|
|
|
mii_get_media_pcs (dev);
|
|
|
|
else
|
|
|
|
mii_get_media (dev);
|
|
|
|
if (np->speed == 1000)
|
|
|
|
np->tx_coalesce = tx_coalesce;
|
2006-09-14 00:24:59 +07:00
|
|
|
else
|
2005-04-17 05:20:36 +07:00
|
|
|
np->tx_coalesce = 1;
|
|
|
|
macctrl = 0;
|
|
|
|
macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
|
|
|
|
macctrl |= (np->full_duplex) ? DuplexSelect : 0;
|
2006-09-14 00:24:59 +07:00
|
|
|
macctrl |= (np->tx_flow) ?
|
2005-04-17 05:20:36 +07:00
|
|
|
TxFlowControlEnable : 0;
|
2006-09-14 00:24:59 +07:00
|
|
|
macctrl |= (np->rx_flow) ?
|
2005-04-17 05:20:36 +07:00
|
|
|
RxFlowControlEnable : 0;
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(MACCtrl, macctrl);
|
2005-04-17 05:20:36 +07:00
|
|
|
np->link_status = 1;
|
|
|
|
netif_carrier_on(dev);
|
|
|
|
} else {
|
|
|
|
printk (KERN_INFO "%s: Link off\n", dev->name);
|
|
|
|
np->link_status = 0;
|
|
|
|
netif_carrier_off(dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* UpdateStats statistics registers */
|
|
|
|
if (int_status & UpdateStats) {
|
|
|
|
get_stats (dev);
|
|
|
|
}
|
|
|
|
|
2006-09-14 00:24:59 +07:00
|
|
|
/* PCI Error, a catastronphic error related to the bus interface
|
2005-04-17 05:20:36 +07:00
|
|
|
occurs, set GlobalReset and HostReset to reset. */
|
|
|
|
if (int_status & HostError) {
|
|
|
|
printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n",
|
|
|
|
dev->name, int_status);
|
2012-03-10 00:09:35 +07:00
|
|
|
dw16(ASICCtrl + 2, GlobalReset | HostReset);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay (500);
|
2015-11-16 04:36:11 +07:00
|
|
|
rio_set_led_mode(dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct net_device_stats *
|
|
|
|
get_stats (struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2012-03-10 00:09:35 +07:00
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
#ifdef MEM_MAPPING
|
|
|
|
int i;
|
|
|
|
#endif
|
|
|
|
unsigned int stat_reg;
|
|
|
|
|
|
|
|
/* All statistics registers need to be acknowledged,
|
|
|
|
else statistic overflow could cause problems */
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.rx_packets += dr32(FramesRcvOk);
|
|
|
|
dev->stats.tx_packets += dr32(FramesXmtOk);
|
|
|
|
dev->stats.rx_bytes += dr32(OctetRcvOk);
|
|
|
|
dev->stats.tx_bytes += dr32(OctetXmtOk);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.multicast = dr32(McstFramesRcvdOk);
|
|
|
|
dev->stats.collisions += dr32(SingleColFrames)
|
2012-03-10 00:09:35 +07:00
|
|
|
+ dr32(MultiColFrames);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* detailed tx errors */
|
2012-03-10 00:09:35 +07:00
|
|
|
stat_reg = dr16(FramesAbortXSColls);
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.tx_aborted_errors += stat_reg;
|
|
|
|
dev->stats.tx_errors += stat_reg;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
stat_reg = dr16(CarrierSenseErrors);
|
2017-04-07 15:17:28 +07:00
|
|
|
dev->stats.tx_carrier_errors += stat_reg;
|
|
|
|
dev->stats.tx_errors += stat_reg;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Clear all other statistic register. */
|
2012-03-10 00:09:35 +07:00
|
|
|
dr32(McstOctetXmtOk);
|
|
|
|
dr16(BcstFramesXmtdOk);
|
|
|
|
dr32(McstFramesXmtdOk);
|
|
|
|
dr16(BcstFramesRcvdOk);
|
|
|
|
dr16(MacControlFramesRcvd);
|
|
|
|
dr16(FrameTooLongErrors);
|
|
|
|
dr16(InRangeLengthErrors);
|
|
|
|
dr16(FramesCheckSeqErrors);
|
|
|
|
dr16(FramesLostRxErrors);
|
|
|
|
dr32(McstOctetXmtOk);
|
|
|
|
dr32(BcstOctetXmtOk);
|
|
|
|
dr32(McstFramesXmtdOk);
|
|
|
|
dr32(FramesWDeferredXmt);
|
|
|
|
dr32(LateCollisions);
|
|
|
|
dr16(BcstFramesXmtdOk);
|
|
|
|
dr16(MacControlFramesXmtd);
|
|
|
|
dr16(FramesWEXDeferal);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#ifdef MEM_MAPPING
|
|
|
|
for (i = 0x100; i <= 0x150; i += 4)
|
2012-03-10 00:09:35 +07:00
|
|
|
dr32(i);
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
2012-03-10 00:09:35 +07:00
|
|
|
dr16(TxJumboFrames);
|
|
|
|
dr16(RxJumboFrames);
|
|
|
|
dr16(TCPCheckSumErrors);
|
|
|
|
dr16(UDPCheckSumErrors);
|
|
|
|
dr16(IPCheckSumErrors);
|
2017-04-07 15:17:28 +07:00
|
|
|
return &dev->stats;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
clear_stats (struct net_device *dev)
|
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
#ifdef MEM_MAPPING
|
|
|
|
int i;
|
2006-09-14 00:24:59 +07:00
|
|
|
#endif
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* All statistics registers need to be acknowledged,
|
|
|
|
else statistic overflow could cause problems */
|
2012-03-10 00:09:35 +07:00
|
|
|
dr32(FramesRcvOk);
|
|
|
|
dr32(FramesXmtOk);
|
|
|
|
dr32(OctetRcvOk);
|
|
|
|
dr32(OctetXmtOk);
|
|
|
|
|
|
|
|
dr32(McstFramesRcvdOk);
|
|
|
|
dr32(SingleColFrames);
|
|
|
|
dr32(MultiColFrames);
|
|
|
|
dr32(LateCollisions);
|
2006-09-14 00:24:59 +07:00
|
|
|
/* detailed rx errors */
|
2012-03-10 00:09:35 +07:00
|
|
|
dr16(FrameTooLongErrors);
|
|
|
|
dr16(InRangeLengthErrors);
|
|
|
|
dr16(FramesCheckSeqErrors);
|
|
|
|
dr16(FramesLostRxErrors);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* detailed tx errors */
|
2012-03-10 00:09:35 +07:00
|
|
|
dr16(FramesAbortXSColls);
|
|
|
|
dr16(CarrierSenseErrors);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Clear all other statistic register. */
|
2012-03-10 00:09:35 +07:00
|
|
|
dr32(McstOctetXmtOk);
|
|
|
|
dr16(BcstFramesXmtdOk);
|
|
|
|
dr32(McstFramesXmtdOk);
|
|
|
|
dr16(BcstFramesRcvdOk);
|
|
|
|
dr16(MacControlFramesRcvd);
|
|
|
|
dr32(McstOctetXmtOk);
|
|
|
|
dr32(BcstOctetXmtOk);
|
|
|
|
dr32(McstFramesXmtdOk);
|
|
|
|
dr32(FramesWDeferredXmt);
|
|
|
|
dr16(BcstFramesXmtdOk);
|
|
|
|
dr16(MacControlFramesXmtd);
|
|
|
|
dr16(FramesWEXDeferal);
|
2005-04-17 05:20:36 +07:00
|
|
|
#ifdef MEM_MAPPING
|
|
|
|
for (i = 0x100; i <= 0x150; i += 4)
|
2012-03-10 00:09:35 +07:00
|
|
|
dr32(i);
|
2006-09-14 00:24:59 +07:00
|
|
|
#endif
|
2012-03-10 00:09:35 +07:00
|
|
|
dr16(TxJumboFrames);
|
|
|
|
dr16(RxJumboFrames);
|
|
|
|
dr16(TCPCheckSumErrors);
|
|
|
|
dr16(UDPCheckSumErrors);
|
|
|
|
dr16(IPCheckSumErrors);
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_multicast (struct net_device *dev)
|
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 hash_table[2];
|
|
|
|
u16 rx_mode = 0;
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
hash_table[0] = hash_table[1] = 0;
|
|
|
|
/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
|
2007-12-23 01:11:18 +07:00
|
|
|
hash_table[1] |= 0x02000000;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (dev->flags & IFF_PROMISC) {
|
|
|
|
/* Receive all frames promiscuously. */
|
|
|
|
rx_mode = ReceiveAllFrames;
|
2006-09-14 00:24:59 +07:00
|
|
|
} else if ((dev->flags & IFF_ALLMULTI) ||
|
2010-02-08 11:30:35 +07:00
|
|
|
(netdev_mc_count(dev) > multicast_filter_limit)) {
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Receive broadcast and multicast frames */
|
|
|
|
rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
|
2010-02-08 11:30:35 +07:00
|
|
|
} else if (!netdev_mc_empty(dev)) {
|
2010-04-02 04:22:57 +07:00
|
|
|
struct netdev_hw_addr *ha;
|
2006-09-14 00:24:59 +07:00
|
|
|
/* Receive broadcast frames and multicast frames filtering
|
2005-04-17 05:20:36 +07:00
|
|
|
by Hashtable */
|
|
|
|
rx_mode =
|
|
|
|
ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
|
2010-04-02 04:22:57 +07:00
|
|
|
netdev_for_each_mc_addr(ha, dev) {
|
2005-04-17 05:20:36 +07:00
|
|
|
int bit, index = 0;
|
2010-04-02 04:22:57 +07:00
|
|
|
int crc = ether_crc_le(ETH_ALEN, ha->addr);
|
2005-04-17 05:20:36 +07:00
|
|
|
/* The inverted high significant 6 bits of CRC are
|
|
|
|
used as an index to hashtable */
|
|
|
|
for (bit = 0; bit < 6; bit++)
|
|
|
|
if (crc & (1 << (31 - bit)))
|
|
|
|
index |= (1 << bit);
|
|
|
|
hash_table[index / 32] |= (1 << (index % 32));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rx_mode = ReceiveBroadcast | ReceiveUnicast;
|
|
|
|
}
|
|
|
|
if (np->vlan) {
|
|
|
|
/* ReceiveVLANMatch field in ReceiveMode */
|
|
|
|
rx_mode |= ReceiveVLANMatch;
|
|
|
|
}
|
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
dw32(HashTable0, hash_table[0]);
|
|
|
|
dw32(HashTable1, hash_table[1]);
|
|
|
|
dw16(ReceiveMode, rx_mode);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2013-01-06 07:44:26 +07:00
|
|
|
|
|
|
|
strlcpy(info->driver, "dl2k", sizeof(info->driver));
|
|
|
|
strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
|
2006-09-14 00:24:59 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2017-01-02 02:49:26 +07:00
|
|
|
static int rio_get_link_ksettings(struct net_device *dev,
|
|
|
|
struct ethtool_link_ksettings *cmd)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2017-01-02 02:49:26 +07:00
|
|
|
u32 supported, advertising;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
if (np->phy_media) {
|
|
|
|
/* fiber device */
|
2017-01-02 02:49:26 +07:00
|
|
|
supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE;
|
|
|
|
advertising = ADVERTISED_Autoneg | ADVERTISED_FIBRE;
|
|
|
|
cmd->base.port = PORT_FIBRE;
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
|
|
|
/* copper device */
|
2017-01-02 02:49:26 +07:00
|
|
|
supported = SUPPORTED_10baseT_Half |
|
2005-04-17 05:20:36 +07:00
|
|
|
SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
|
|
|
|
| SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
|
|
|
|
SUPPORTED_Autoneg | SUPPORTED_MII;
|
2017-01-02 02:49:26 +07:00
|
|
|
advertising = ADVERTISED_10baseT_Half |
|
2005-04-17 05:20:36 +07:00
|
|
|
ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
|
2017-01-02 02:49:26 +07:00
|
|
|
ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full |
|
2005-04-17 05:20:36 +07:00
|
|
|
ADVERTISED_Autoneg | ADVERTISED_MII;
|
2017-01-02 02:49:26 +07:00
|
|
|
cmd->base.port = PORT_MII;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2017-01-02 02:49:26 +07:00
|
|
|
if (np->link_status) {
|
|
|
|
cmd->base.speed = np->speed;
|
|
|
|
cmd->base.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
2017-01-02 02:49:26 +07:00
|
|
|
cmd->base.speed = SPEED_UNKNOWN;
|
|
|
|
cmd->base.duplex = DUPLEX_UNKNOWN;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2017-01-02 02:49:26 +07:00
|
|
|
if (np->an_enable)
|
|
|
|
cmd->base.autoneg = AUTONEG_ENABLE;
|
2005-04-17 05:20:36 +07:00
|
|
|
else
|
2017-01-02 02:49:26 +07:00
|
|
|
cmd->base.autoneg = AUTONEG_DISABLE;
|
|
|
|
|
|
|
|
cmd->base.phy_address = np->phy_addr;
|
|
|
|
|
|
|
|
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
|
|
|
|
supported);
|
|
|
|
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
|
|
|
|
advertising);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2017-01-02 02:49:26 +07:00
|
|
|
static int rio_set_link_ksettings(struct net_device *dev,
|
|
|
|
const struct ethtool_link_ksettings *cmd)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2017-01-02 02:49:26 +07:00
|
|
|
u32 speed = cmd->base.speed;
|
|
|
|
u8 duplex = cmd->base.duplex;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
netif_carrier_off(dev);
|
2017-01-02 02:49:26 +07:00
|
|
|
if (cmd->base.autoneg == AUTONEG_ENABLE) {
|
|
|
|
if (np->an_enable) {
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
2017-01-02 02:49:26 +07:00
|
|
|
} else {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->an_enable = 1;
|
|
|
|
mii_set_media(dev);
|
2006-09-14 00:24:59 +07:00
|
|
|
return 0;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
|
|
|
np->an_enable = 0;
|
|
|
|
if (np->speed == 1000) {
|
2017-01-02 02:49:26 +07:00
|
|
|
speed = SPEED_100;
|
|
|
|
duplex = DUPLEX_FULL;
|
2005-04-17 05:20:36 +07:00
|
|
|
printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
|
|
|
|
}
|
2017-01-02 02:49:26 +07:00
|
|
|
switch (speed) {
|
2011-04-28 01:32:39 +07:00
|
|
|
case SPEED_10:
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 10;
|
2017-01-02 02:49:26 +07:00
|
|
|
np->full_duplex = (duplex == DUPLEX_FULL);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
2011-04-28 01:32:39 +07:00
|
|
|
case SPEED_100:
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 100;
|
2017-01-02 02:49:26 +07:00
|
|
|
np->full_duplex = (duplex == DUPLEX_FULL);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
2011-04-28 01:32:39 +07:00
|
|
|
case SPEED_1000: /* not supported */
|
2005-04-17 05:20:36 +07:00
|
|
|
default:
|
2006-09-14 00:24:59 +07:00
|
|
|
return -EINVAL;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
mii_set_media(dev);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 rio_get_link(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
return np->link_status;
|
|
|
|
}
|
|
|
|
|
2006-09-14 01:30:00 +07:00
|
|
|
static const struct ethtool_ops ethtool_ops = {
|
2005-04-17 05:20:36 +07:00
|
|
|
.get_drvinfo = rio_get_drvinfo,
|
|
|
|
.get_link = rio_get_link,
|
2017-01-02 02:49:26 +07:00
|
|
|
.get_link_ksettings = rio_get_link_ksettings,
|
|
|
|
.set_link_ksettings = rio_set_link_ksettings,
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
|
|
|
|
{
|
|
|
|
int phy_addr;
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2012-04-25 21:32:09 +07:00
|
|
|
struct mii_ioctl_data *miidata = if_mii(rq);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
phy_addr = np->phy_addr;
|
|
|
|
switch (cmd) {
|
2012-04-25 21:32:09 +07:00
|
|
|
case SIOCGMIIPHY:
|
|
|
|
miidata->phy_id = phy_addr;
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
2012-04-25 21:32:09 +07:00
|
|
|
case SIOCGMIIREG:
|
|
|
|
miidata->val_out = mii_read (dev, phy_addr, miidata->reg_num);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
2012-04-25 21:32:09 +07:00
|
|
|
case SIOCSMIIREG:
|
|
|
|
if (!capable(CAP_NET_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
mii_write (dev, phy_addr, miidata->reg_num, miidata->val_in);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define EEP_READ 0x0200
|
|
|
|
#define EEP_BUSY 0x8000
|
|
|
|
/* Read the EEPROM word */
|
|
|
|
/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
|
2012-03-10 00:09:35 +07:00
|
|
|
static int read_eeprom(struct netdev_private *np, int eep_addr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
void __iomem *ioaddr = np->eeprom_addr;
|
2005-04-17 05:20:36 +07:00
|
|
|
int i = 1000;
|
2012-03-10 00:09:35 +07:00
|
|
|
|
|
|
|
dw16(EepromCtrl, EEP_READ | (eep_addr & 0xff));
|
2005-04-17 05:20:36 +07:00
|
|
|
while (i-- > 0) {
|
2012-03-10 00:09:35 +07:00
|
|
|
if (!(dr16(EepromCtrl) & EEP_BUSY))
|
|
|
|
return dr16(EepromData);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum phy_ctrl_bits {
|
|
|
|
MII_READ = 0x00, MII_CLK = 0x01, MII_DATA1 = 0x02, MII_WRITE = 0x04,
|
|
|
|
MII_DUPLEX = 0x08,
|
|
|
|
};
|
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
#define mii_delay() dr8(PhyCtrl)
|
2005-04-17 05:20:36 +07:00
|
|
|
static void
|
|
|
|
mii_sendbit (struct net_device *dev, u32 data)
|
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
|
|
|
|
|
|
|
data = ((data) ? MII_DATA1 : 0) | (dr8(PhyCtrl) & 0xf8) | MII_WRITE;
|
|
|
|
dw8(PhyCtrl, data);
|
2005-04-17 05:20:36 +07:00
|
|
|
mii_delay ();
|
2012-03-10 00:09:35 +07:00
|
|
|
dw8(PhyCtrl, data | MII_CLK);
|
2005-04-17 05:20:36 +07:00
|
|
|
mii_delay ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
mii_getbit (struct net_device *dev)
|
|
|
|
{
|
2012-03-10 00:09:35 +07:00
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
void __iomem *ioaddr = np->ioaddr;
|
2005-04-17 05:20:36 +07:00
|
|
|
u8 data;
|
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
data = (dr8(PhyCtrl) & 0xf8) | MII_READ;
|
|
|
|
dw8(PhyCtrl, data);
|
2005-04-17 05:20:36 +07:00
|
|
|
mii_delay ();
|
2012-03-10 00:09:35 +07:00
|
|
|
dw8(PhyCtrl, data | MII_CLK);
|
2005-04-17 05:20:36 +07:00
|
|
|
mii_delay ();
|
2012-03-10 00:09:35 +07:00
|
|
|
return (dr8(PhyCtrl) >> 1) & 1;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mii_send_bits (struct net_device *dev, u32 data, int len)
|
|
|
|
{
|
|
|
|
int i;
|
2012-03-10 00:09:35 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
for (i = len - 1; i >= 0; i--) {
|
|
|
|
mii_sendbit (dev, data & (1 << i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
mii_read (struct net_device *dev, int phy_addr, int reg_num)
|
|
|
|
{
|
|
|
|
u32 cmd;
|
|
|
|
int i;
|
|
|
|
u32 retval = 0;
|
|
|
|
|
|
|
|
/* Preamble */
|
|
|
|
mii_send_bits (dev, 0xffffffff, 32);
|
|
|
|
/* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
|
|
|
|
/* ST,OP = 0110'b for read operation */
|
|
|
|
cmd = (0x06 << 10 | phy_addr << 5 | reg_num);
|
|
|
|
mii_send_bits (dev, cmd, 14);
|
|
|
|
/* Turnaround */
|
|
|
|
if (mii_getbit (dev))
|
|
|
|
goto err_out;
|
|
|
|
/* Read data */
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
retval |= mii_getbit (dev);
|
|
|
|
retval <<= 1;
|
|
|
|
}
|
|
|
|
/* End cycle */
|
|
|
|
mii_getbit (dev);
|
|
|
|
return (retval >> 1) & 0xffff;
|
|
|
|
|
|
|
|
err_out:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int
|
|
|
|
mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data)
|
|
|
|
{
|
|
|
|
u32 cmd;
|
|
|
|
|
|
|
|
/* Preamble */
|
|
|
|
mii_send_bits (dev, 0xffffffff, 32);
|
|
|
|
/* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
|
|
|
|
/* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x5002 for write */
|
|
|
|
cmd = (0x5002 << 16) | (phy_addr << 23) | (reg_num << 18) | data;
|
|
|
|
mii_send_bits (dev, cmd, 32);
|
|
|
|
/* End cycle */
|
|
|
|
mii_getbit (dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int
|
|
|
|
mii_wait_link (struct net_device *dev, int wait)
|
|
|
|
{
|
2008-01-13 21:18:05 +07:00
|
|
|
__u16 bmsr;
|
2005-04-17 05:20:36 +07:00
|
|
|
int phy_addr;
|
|
|
|
struct netdev_private *np;
|
|
|
|
|
|
|
|
np = netdev_priv(dev);
|
|
|
|
phy_addr = np->phy_addr;
|
|
|
|
|
|
|
|
do {
|
2008-01-13 21:18:05 +07:00
|
|
|
bmsr = mii_read (dev, phy_addr, MII_BMSR);
|
2011-08-21 23:32:05 +07:00
|
|
|
if (bmsr & BMSR_LSTATUS)
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
|
|
|
mdelay (1);
|
|
|
|
} while (--wait > 0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
static int
|
|
|
|
mii_get_media (struct net_device *dev)
|
|
|
|
{
|
2008-01-13 21:17:55 +07:00
|
|
|
__u16 negotiate;
|
2008-01-13 21:18:05 +07:00
|
|
|
__u16 bmsr;
|
2008-01-13 21:18:15 +07:00
|
|
|
__u16 mscr;
|
|
|
|
__u16 mssr;
|
2005-04-17 05:20:36 +07:00
|
|
|
int phy_addr;
|
|
|
|
struct netdev_private *np;
|
|
|
|
|
|
|
|
np = netdev_priv(dev);
|
|
|
|
phy_addr = np->phy_addr;
|
|
|
|
|
2008-01-13 21:18:05 +07:00
|
|
|
bmsr = mii_read (dev, phy_addr, MII_BMSR);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (np->an_enable) {
|
2011-08-21 23:32:05 +07:00
|
|
|
if (!(bmsr & BMSR_ANEGCOMPLETE)) {
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Auto-Negotiation not completed */
|
|
|
|
return -1;
|
|
|
|
}
|
2011-08-21 23:32:05 +07:00
|
|
|
negotiate = mii_read (dev, phy_addr, MII_ADVERTISE) &
|
|
|
|
mii_read (dev, phy_addr, MII_LPA);
|
|
|
|
mscr = mii_read (dev, phy_addr, MII_CTRL1000);
|
|
|
|
mssr = mii_read (dev, phy_addr, MII_STAT1000);
|
|
|
|
if (mscr & ADVERTISE_1000FULL && mssr & LPA_1000FULL) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 1000;
|
|
|
|
np->full_duplex = 1;
|
|
|
|
printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
|
2011-08-21 23:32:05 +07:00
|
|
|
} else if (mscr & ADVERTISE_1000HALF && mssr & LPA_1000HALF) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 1000;
|
|
|
|
np->full_duplex = 0;
|
|
|
|
printk (KERN_INFO "Auto 1000 Mbps, Half duplex\n");
|
2011-08-21 23:32:05 +07:00
|
|
|
} else if (negotiate & ADVERTISE_100FULL) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 100;
|
|
|
|
np->full_duplex = 1;
|
|
|
|
printk (KERN_INFO "Auto 100 Mbps, Full duplex\n");
|
2011-08-21 23:32:05 +07:00
|
|
|
} else if (negotiate & ADVERTISE_100HALF) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 100;
|
|
|
|
np->full_duplex = 0;
|
|
|
|
printk (KERN_INFO "Auto 100 Mbps, Half duplex\n");
|
2011-08-21 23:32:05 +07:00
|
|
|
} else if (negotiate & ADVERTISE_10FULL) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 10;
|
|
|
|
np->full_duplex = 1;
|
|
|
|
printk (KERN_INFO "Auto 10 Mbps, Full duplex\n");
|
2011-08-21 23:32:05 +07:00
|
|
|
} else if (negotiate & ADVERTISE_10HALF) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->speed = 10;
|
|
|
|
np->full_duplex = 0;
|
|
|
|
printk (KERN_INFO "Auto 10 Mbps, Half duplex\n");
|
|
|
|
}
|
2011-08-21 23:32:05 +07:00
|
|
|
if (negotiate & ADVERTISE_PAUSE_CAP) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->tx_flow &= 1;
|
|
|
|
np->rx_flow &= 1;
|
2011-08-21 23:32:05 +07:00
|
|
|
} else if (negotiate & ADVERTISE_PAUSE_ASYM) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->tx_flow = 0;
|
|
|
|
np->rx_flow &= 1;
|
|
|
|
}
|
|
|
|
/* else tx_flow, rx_flow = user select */
|
|
|
|
} else {
|
2008-01-13 21:17:45 +07:00
|
|
|
__u16 bmcr = mii_read (dev, phy_addr, MII_BMCR);
|
2011-08-21 23:32:05 +07:00
|
|
|
switch (bmcr & (BMCR_SPEED100 | BMCR_SPEED1000)) {
|
|
|
|
case BMCR_SPEED1000:
|
2008-01-13 21:17:45 +07:00
|
|
|
printk (KERN_INFO "Operating at 1000 Mbps, ");
|
|
|
|
break;
|
2011-08-21 23:32:05 +07:00
|
|
|
case BMCR_SPEED100:
|
2005-04-17 05:20:36 +07:00
|
|
|
printk (KERN_INFO "Operating at 100 Mbps, ");
|
2008-01-13 21:17:45 +07:00
|
|
|
break;
|
|
|
|
case 0:
|
2005-04-17 05:20:36 +07:00
|
|
|
printk (KERN_INFO "Operating at 10 Mbps, ");
|
|
|
|
}
|
2011-08-21 23:32:05 +07:00
|
|
|
if (bmcr & BMCR_FULLDPLX) {
|
2009-07-07 03:05:40 +07:00
|
|
|
printk (KERN_CONT "Full duplex\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
2009-07-07 03:05:40 +07:00
|
|
|
printk (KERN_CONT "Half duplex\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
}
|
2006-09-14 00:24:59 +07:00
|
|
|
if (np->tx_flow)
|
2005-04-17 05:20:36 +07:00
|
|
|
printk(KERN_INFO "Enable Tx Flow Control\n");
|
2006-09-14 00:24:59 +07:00
|
|
|
else
|
2005-04-17 05:20:36 +07:00
|
|
|
printk(KERN_INFO "Disable Tx Flow Control\n");
|
|
|
|
if (np->rx_flow)
|
|
|
|
printk(KERN_INFO "Enable Rx Flow Control\n");
|
|
|
|
else
|
|
|
|
printk(KERN_INFO "Disable Rx Flow Control\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
mii_set_media (struct net_device *dev)
|
|
|
|
{
|
2008-01-13 21:18:15 +07:00
|
|
|
__u16 pscr;
|
2008-01-13 21:17:45 +07:00
|
|
|
__u16 bmcr;
|
2008-01-13 21:18:05 +07:00
|
|
|
__u16 bmsr;
|
2008-01-13 21:17:55 +07:00
|
|
|
__u16 anar;
|
2005-04-17 05:20:36 +07:00
|
|
|
int phy_addr;
|
|
|
|
struct netdev_private *np;
|
|
|
|
np = netdev_priv(dev);
|
|
|
|
phy_addr = np->phy_addr;
|
|
|
|
|
|
|
|
/* Does user set speed? */
|
|
|
|
if (np->an_enable) {
|
|
|
|
/* Advertise capabilities */
|
2008-01-13 21:18:05 +07:00
|
|
|
bmsr = mii_read (dev, phy_addr, MII_BMSR);
|
2011-08-21 23:32:05 +07:00
|
|
|
anar = mii_read (dev, phy_addr, MII_ADVERTISE) &
|
|
|
|
~(ADVERTISE_100FULL | ADVERTISE_10FULL |
|
|
|
|
ADVERTISE_100HALF | ADVERTISE_10HALF |
|
|
|
|
ADVERTISE_100BASE4);
|
|
|
|
if (bmsr & BMSR_100FULL)
|
|
|
|
anar |= ADVERTISE_100FULL;
|
|
|
|
if (bmsr & BMSR_100HALF)
|
|
|
|
anar |= ADVERTISE_100HALF;
|
|
|
|
if (bmsr & BMSR_100BASE4)
|
|
|
|
anar |= ADVERTISE_100BASE4;
|
|
|
|
if (bmsr & BMSR_10FULL)
|
|
|
|
anar |= ADVERTISE_10FULL;
|
|
|
|
if (bmsr & BMSR_10HALF)
|
|
|
|
anar |= ADVERTISE_10HALF;
|
|
|
|
anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
|
|
|
|
mii_write (dev, phy_addr, MII_ADVERTISE, anar);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Enable Auto crossover */
|
2008-01-13 21:18:15 +07:00
|
|
|
pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
|
|
|
|
pscr |= 3 << 5; /* 11'b */
|
|
|
|
mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Soft reset PHY */
|
2011-08-21 23:32:05 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, BMCR_RESET);
|
|
|
|
bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
|
2008-01-13 21:17:45 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, bmcr);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay(1);
|
|
|
|
} else {
|
|
|
|
/* Force speed setting */
|
|
|
|
/* 1) Disable Auto crossover */
|
2008-01-13 21:18:15 +07:00
|
|
|
pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
|
|
|
|
pscr &= ~(3 << 5);
|
|
|
|
mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* 2) PHY Reset */
|
2008-01-13 21:17:45 +07:00
|
|
|
bmcr = mii_read (dev, phy_addr, MII_BMCR);
|
2011-08-21 23:32:05 +07:00
|
|
|
bmcr |= BMCR_RESET;
|
2008-01-13 21:17:45 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, bmcr);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* 3) Power Down */
|
2008-01-13 21:17:45 +07:00
|
|
|
bmcr = 0x1940; /* must be 0x1940 */
|
|
|
|
mii_write (dev, phy_addr, MII_BMCR, bmcr);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay (100); /* wait a certain time */
|
|
|
|
|
|
|
|
/* 4) Advertise nothing */
|
2011-08-21 23:32:05 +07:00
|
|
|
mii_write (dev, phy_addr, MII_ADVERTISE, 0);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* 5) Set media and Power Up */
|
2011-08-21 23:32:05 +07:00
|
|
|
bmcr = BMCR_PDOWN;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (np->speed == 100) {
|
2011-08-21 23:32:05 +07:00
|
|
|
bmcr |= BMCR_SPEED100;
|
2005-04-17 05:20:36 +07:00
|
|
|
printk (KERN_INFO "Manual 100 Mbps, ");
|
|
|
|
} else if (np->speed == 10) {
|
|
|
|
printk (KERN_INFO "Manual 10 Mbps, ");
|
|
|
|
}
|
|
|
|
if (np->full_duplex) {
|
2011-08-21 23:32:05 +07:00
|
|
|
bmcr |= BMCR_FULLDPLX;
|
2009-07-07 03:05:40 +07:00
|
|
|
printk (KERN_CONT "Full duplex\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
2009-07-07 03:05:40 +07:00
|
|
|
printk (KERN_CONT "Half duplex\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
/* Set 1000BaseT Master/Slave setting */
|
2011-08-21 23:32:05 +07:00
|
|
|
mscr = mii_read (dev, phy_addr, MII_CTRL1000);
|
2008-01-13 21:18:15 +07:00
|
|
|
mscr |= MII_MSCR_CFG_ENABLE;
|
|
|
|
mscr &= ~MII_MSCR_CFG_VALUE = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
2008-01-13 21:17:45 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, bmcr);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay(10);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
mii_get_media_pcs (struct net_device *dev)
|
|
|
|
{
|
2008-01-13 21:17:55 +07:00
|
|
|
__u16 negotiate;
|
2008-01-13 21:18:05 +07:00
|
|
|
__u16 bmsr;
|
2005-04-17 05:20:36 +07:00
|
|
|
int phy_addr;
|
|
|
|
struct netdev_private *np;
|
|
|
|
|
|
|
|
np = netdev_priv(dev);
|
|
|
|
phy_addr = np->phy_addr;
|
|
|
|
|
2008-01-13 21:18:05 +07:00
|
|
|
bmsr = mii_read (dev, phy_addr, PCS_BMSR);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (np->an_enable) {
|
2011-08-21 23:32:05 +07:00
|
|
|
if (!(bmsr & BMSR_ANEGCOMPLETE)) {
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Auto-Negotiation not completed */
|
|
|
|
return -1;
|
|
|
|
}
|
2008-01-13 21:17:55 +07:00
|
|
|
negotiate = mii_read (dev, phy_addr, PCS_ANAR) &
|
2005-04-17 05:20:36 +07:00
|
|
|
mii_read (dev, phy_addr, PCS_ANLPAR);
|
|
|
|
np->speed = 1000;
|
2008-01-13 21:17:55 +07:00
|
|
|
if (negotiate & PCS_ANAR_FULL_DUPLEX) {
|
2005-04-17 05:20:36 +07:00
|
|
|
printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
|
|
|
|
np->full_duplex = 1;
|
|
|
|
} else {
|
|
|
|
printk (KERN_INFO "Auto 1000 Mbps, half duplex\n");
|
|
|
|
np->full_duplex = 0;
|
|
|
|
}
|
2008-01-13 21:17:55 +07:00
|
|
|
if (negotiate & PCS_ANAR_PAUSE) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->tx_flow &= 1;
|
|
|
|
np->rx_flow &= 1;
|
2008-01-13 21:17:55 +07:00
|
|
|
} else if (negotiate & PCS_ANAR_ASYMMETRIC) {
|
2005-04-17 05:20:36 +07:00
|
|
|
np->tx_flow = 0;
|
|
|
|
np->rx_flow &= 1;
|
|
|
|
}
|
|
|
|
/* else tx_flow, rx_flow = user select */
|
|
|
|
} else {
|
2008-01-13 21:17:45 +07:00
|
|
|
__u16 bmcr = mii_read (dev, phy_addr, PCS_BMCR);
|
2005-04-17 05:20:36 +07:00
|
|
|
printk (KERN_INFO "Operating at 1000 Mbps, ");
|
2011-08-21 23:32:05 +07:00
|
|
|
if (bmcr & BMCR_FULLDPLX) {
|
2009-07-07 03:05:40 +07:00
|
|
|
printk (KERN_CONT "Full duplex\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
2009-07-07 03:05:40 +07:00
|
|
|
printk (KERN_CONT "Half duplex\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
}
|
2006-09-14 00:24:59 +07:00
|
|
|
if (np->tx_flow)
|
2005-04-17 05:20:36 +07:00
|
|
|
printk(KERN_INFO "Enable Tx Flow Control\n");
|
2006-09-14 00:24:59 +07:00
|
|
|
else
|
2005-04-17 05:20:36 +07:00
|
|
|
printk(KERN_INFO "Disable Tx Flow Control\n");
|
|
|
|
if (np->rx_flow)
|
|
|
|
printk(KERN_INFO "Enable Rx Flow Control\n");
|
|
|
|
else
|
|
|
|
printk(KERN_INFO "Disable Rx Flow Control\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
mii_set_media_pcs (struct net_device *dev)
|
|
|
|
{
|
2008-01-13 21:17:45 +07:00
|
|
|
__u16 bmcr;
|
2008-01-13 21:18:15 +07:00
|
|
|
__u16 esr;
|
2008-01-13 21:17:55 +07:00
|
|
|
__u16 anar;
|
2005-04-17 05:20:36 +07:00
|
|
|
int phy_addr;
|
|
|
|
struct netdev_private *np;
|
|
|
|
np = netdev_priv(dev);
|
|
|
|
phy_addr = np->phy_addr;
|
|
|
|
|
|
|
|
/* Auto-Negotiation? */
|
|
|
|
if (np->an_enable) {
|
|
|
|
/* Advertise capabilities */
|
2008-01-13 21:18:15 +07:00
|
|
|
esr = mii_read (dev, phy_addr, PCS_ESR);
|
2011-08-21 23:32:05 +07:00
|
|
|
anar = mii_read (dev, phy_addr, MII_ADVERTISE) &
|
2008-01-13 21:17:55 +07:00
|
|
|
~PCS_ANAR_HALF_DUPLEX &
|
|
|
|
~PCS_ANAR_FULL_DUPLEX;
|
2008-01-13 21:18:15 +07:00
|
|
|
if (esr & (MII_ESR_1000BT_HD | MII_ESR_1000BX_HD))
|
2008-01-13 21:17:55 +07:00
|
|
|
anar |= PCS_ANAR_HALF_DUPLEX;
|
2008-01-13 21:18:15 +07:00
|
|
|
if (esr & (MII_ESR_1000BT_FD | MII_ESR_1000BX_FD))
|
2008-01-13 21:17:55 +07:00
|
|
|
anar |= PCS_ANAR_FULL_DUPLEX;
|
|
|
|
anar |= PCS_ANAR_PAUSE | PCS_ANAR_ASYMMETRIC;
|
2011-08-21 23:32:05 +07:00
|
|
|
mii_write (dev, phy_addr, MII_ADVERTISE, anar);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Soft reset PHY */
|
2011-08-21 23:32:05 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, BMCR_RESET);
|
|
|
|
bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
|
2008-01-13 21:17:45 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, bmcr);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay(1);
|
|
|
|
} else {
|
|
|
|
/* Force speed setting */
|
|
|
|
/* PHY Reset */
|
2011-08-21 23:32:05 +07:00
|
|
|
bmcr = BMCR_RESET;
|
2008-01-13 21:17:45 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, bmcr);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay(10);
|
|
|
|
if (np->full_duplex) {
|
2011-08-21 23:32:05 +07:00
|
|
|
bmcr = BMCR_FULLDPLX;
|
2005-04-17 05:20:36 +07:00
|
|
|
printk (KERN_INFO "Manual full duplex\n");
|
|
|
|
} else {
|
2008-01-13 21:17:45 +07:00
|
|
|
bmcr = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
printk (KERN_INFO "Manual half duplex\n");
|
|
|
|
}
|
2008-01-13 21:17:45 +07:00
|
|
|
mii_write (dev, phy_addr, MII_BMCR, bmcr);
|
2005-04-17 05:20:36 +07:00
|
|
|
mdelay(10);
|
|
|
|
|
|
|
|
/* Advertise nothing */
|
2011-08-21 23:32:05 +07:00
|
|
|
mii_write (dev, phy_addr, MII_ADVERTISE, 0);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
rio_close (struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
2012-03-10 00:09:35 +07:00
|
|
|
struct pci_dev *pdev = np->pdev;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
netif_stop_queue (dev);
|
|
|
|
|
2015-11-20 02:13:05 +07:00
|
|
|
rio_hw_stop(dev);
|
2008-06-27 13:20:20 +07:00
|
|
|
|
2012-03-10 00:09:35 +07:00
|
|
|
free_irq(pdev->irq, dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
del_timer_sync (&np->timer);
|
2006-09-14 00:24:59 +07:00
|
|
|
|
2015-11-20 02:13:04 +07:00
|
|
|
free_list(dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-03 21:23:07 +07:00
|
|
|
static void
|
2005-04-17 05:20:36 +07:00
|
|
|
rio_remove1 (struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
struct net_device *dev = pci_get_drvdata (pdev);
|
|
|
|
|
|
|
|
if (dev) {
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
|
|
|
|
unregister_netdev (dev);
|
|
|
|
pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring,
|
|
|
|
np->rx_ring_dma);
|
|
|
|
pci_free_consistent (pdev, TX_TOTAL_SIZE, np->tx_ring,
|
|
|
|
np->tx_ring_dma);
|
|
|
|
#ifdef MEM_MAPPING
|
2012-03-10 00:09:35 +07:00
|
|
|
pci_iounmap(pdev, np->ioaddr);
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
2012-03-10 00:09:35 +07:00
|
|
|
pci_iounmap(pdev, np->eeprom_addr);
|
2005-04-17 05:20:36 +07:00
|
|
|
free_netdev (dev);
|
|
|
|
pci_release_regions (pdev);
|
|
|
|
pci_disable_device (pdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-20 02:13:06 +07:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
|
static int rio_suspend(struct device *device)
|
|
|
|
{
|
|
|
|
struct net_device *dev = dev_get_drvdata(device);
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
|
|
|
|
if (!netif_running(dev))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
netif_device_detach(dev);
|
|
|
|
del_timer_sync(&np->timer);
|
|
|
|
rio_hw_stop(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rio_resume(struct device *device)
|
|
|
|
{
|
|
|
|
struct net_device *dev = dev_get_drvdata(device);
|
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
|
|
|
|
|
if (!netif_running(dev))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rio_reset_ring(np);
|
|
|
|
rio_hw_init(dev);
|
|
|
|
np->timer.expires = jiffies + 1 * HZ;
|
|
|
|
add_timer(&np->timer);
|
|
|
|
netif_device_attach(dev);
|
|
|
|
dl2k_enable_int(np);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SIMPLE_DEV_PM_OPS(rio_pm_ops, rio_suspend, rio_resume);
|
|
|
|
#define RIO_PM_OPS (&rio_pm_ops)
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#define RIO_PM_OPS NULL
|
|
|
|
|
|
|
|
#endif /* CONFIG_PM_SLEEP */
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static struct pci_driver rio_driver = {
|
|
|
|
.name = "dl2k",
|
|
|
|
.id_table = rio_pci_tbl,
|
|
|
|
.probe = rio_probe1,
|
2012-12-03 21:23:07 +07:00
|
|
|
.remove = rio_remove1,
|
2015-11-20 02:13:06 +07:00
|
|
|
.driver.pm = RIO_PM_OPS,
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
2012-10-26 16:29:00 +07:00
|
|
|
module_pci_driver(rio_driver);
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
2006-09-14 00:24:59 +07:00
|
|
|
|
|
|
|
Compile command:
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c
|
|
|
|
|
2018-12-04 08:43:28 +07:00
|
|
|
Read Documentation/networking/device_drivers/dlink/dl2k.txt for details.
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
*/
|
|
|
|
|