Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorDavid S. Miller <davem@davemloft.net>
Tue, 29 Jan 2013 20:32:13 +0000 (15:32 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 29 Jan 2013 20:32:13 +0000 (15:32 -0500)
Bring in the 'net' tree so that we can get some ipv4/ipv6 bug
fixes that some net-next work will build upon.

Signed-off-by: David S. Miller <davem@davemloft.net>
850 files changed:
Documentation/networking/00-INDEX
Documentation/networking/DLINK.txt [deleted file]
Documentation/networking/cs89x0.txt
Documentation/networking/depca.txt [deleted file]
Documentation/networking/ewrk3.txt [deleted file]
Documentation/networking/filter.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/multicast.txt [deleted file]
Documentation/networking/netconsole.txt
Documentation/networking/nf_conntrack-sysctl.txt [new file with mode: 0644]
Documentation/networking/operstates.txt
Documentation/networking/phy.txt
Documentation/nfc/nfc-hci.txt
Documentation/nfc/nfc-pn544.txt
MAINTAINERS
arch/alpha/include/uapi/asm/socket.h
arch/avr32/include/uapi/asm/socket.h
arch/cris/include/uapi/asm/socket.h
arch/frv/include/uapi/asm/socket.h
arch/h8300/include/uapi/asm/socket.h
arch/ia64/include/uapi/asm/socket.h
arch/m32r/include/uapi/asm/socket.h
arch/mips/bcm47xx/serial.c
arch/mips/include/uapi/asm/socket.h
arch/mn10300/include/uapi/asm/socket.h
arch/parisc/include/uapi/asm/socket.h
arch/powerpc/include/uapi/asm/socket.h
arch/s390/include/uapi/asm/socket.h
arch/sparc/include/uapi/asm/socket.h
arch/um/drivers/net_kern.c
arch/um/include/shared/net_kern.h
arch/x86/crypto/aesni-intel_glue.c
arch/xtensa/include/uapi/asm/socket.h
crypto/ctr.c
crypto/tcrypt.c
crypto/tcrypt.h
drivers/bcma/bcma_private.h
drivers/bcma/driver_chipcommon.c
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/driver_mips.c
drivers/bcma/driver_pci_host.c
drivers/bcma/main.c
drivers/firewire/net.c
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
drivers/isdn/divert/divert_init.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/divert/isdn_divert.h
drivers/isdn/gigaset/common.c
drivers/isdn/gigaset/ev-layer.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/gigaset/interface.c
drivers/net/Space.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/at91_can.c
drivers/net/can/c_can/Kconfig
drivers/net/can/c_can/c_can.c
drivers/net/can/cc770/Kconfig
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/led.c [new file with mode: 0644]
drivers/net/can/mcp251x.c
drivers/net/can/mscan/Kconfig
drivers/net/can/sja1000/Kconfig
drivers/net/can/sja1000/sja1000.c
drivers/net/can/slcan.c
drivers/net/can/softing/Kconfig
drivers/net/can/ti_hecc.c
drivers/net/can/usb/Kconfig
drivers/net/can/usb/Makefile
drivers/net/can/usb/usb_8dev.c [new file with mode: 0644]
drivers/net/cris/eth_v10.c
drivers/net/dsa/mv88e6060.c
drivers/net/dsa/mv88e6123_61_65.c
drivers/net/dsa/mv88e6131.c
drivers/net/dsa/mv88e6xxx.c
drivers/net/dsa/mv88e6xxx.h
drivers/net/dummy.c
drivers/net/ethernet/3com/3c501.c [deleted file]
drivers/net/ethernet/3com/3c501.h [deleted file]
drivers/net/ethernet/3com/3c509.c
drivers/net/ethernet/3com/3c515.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/3com/Kconfig
drivers/net/ethernet/3com/Makefile
drivers/net/ethernet/8390/3c503.c [deleted file]
drivers/net/ethernet/8390/3c503.h [deleted file]
drivers/net/ethernet/8390/Kconfig
drivers/net/ethernet/8390/Makefile
drivers/net/ethernet/8390/ac3200.c [deleted file]
drivers/net/ethernet/8390/ax88796.c
drivers/net/ethernet/8390/e2100.c [deleted file]
drivers/net/ethernet/8390/es3210.c [deleted file]
drivers/net/ethernet/8390/hp-plus.c [deleted file]
drivers/net/ethernet/8390/hp.c [deleted file]
drivers/net/ethernet/8390/lne390.c [deleted file]
drivers/net/ethernet/8390/ne2k-pci.c
drivers/net/ethernet/8390/ne3210.c [deleted file]
drivers/net/ethernet/8390/smc-ultra32.c [deleted file]
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/adi/bfin_mac.c
drivers/net/ethernet/aeroflex/greth.c
drivers/net/ethernet/amd/Kconfig
drivers/net/ethernet/amd/Makefile
drivers/net/ethernet/amd/au1000_eth.c
drivers/net/ethernet/amd/depca.c [deleted file]
drivers/net/ethernet/amd/depca.h [deleted file]
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/amd/sunlance.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/atheros/atlx/atl1.c
drivers/net/ethernet/atheros/atlx/atl2.c
drivers/net/ethernet/atheros/atlx/atlx.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/Makefile
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bgmac.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/bgmac.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2x/Makefile
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic_if.h
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/calxeda/xgmac.c
drivers/net/ethernet/chelsio/cxgb/cxgb2.c
drivers/net/ethernet/chelsio/cxgb/sge.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
drivers/net/ethernet/chelsio/cxgb3/sge.c
drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/cirrus/ep93xx_eth.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/dec/Kconfig
drivers/net/ethernet/dec/Makefile
drivers/net/ethernet/dec/ewrk3.c [deleted file]
drivers/net/ethernet/dec/ewrk3.h [deleted file]
drivers/net/ethernet/dlink/Kconfig
drivers/net/ethernet/dlink/Makefile
drivers/net/ethernet/dlink/de600.c [deleted file]
drivers/net/ethernet/dlink/de600.h [deleted file]
drivers/net/ethernet/dlink/de620.c [deleted file]
drivers/net/ethernet/dlink/de620.h [deleted file]
drivers/net/ethernet/dlink/dl2k.c
drivers/net/ethernet/dlink/sundance.c
drivers/net/ethernet/dnet.c
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/ethoc.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/faraday/ftmac100.c
drivers/net/ethernet/freescale/Kconfig
drivers/net/ethernet/freescale/Makefile
drivers/net/ethernet/freescale/fec.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/freescale/ucc_geth_ethtool.c
drivers/net/ethernet/fujitsu/Kconfig
drivers/net/ethernet/fujitsu/Makefile
drivers/net/ethernet/fujitsu/at1700.c [deleted file]
drivers/net/ethernet/fujitsu/eth16i.c [deleted file]
drivers/net/ethernet/i825xx/3c505.c [deleted file]
drivers/net/ethernet/i825xx/3c505.h [deleted file]
drivers/net/ethernet/i825xx/3c507.c [deleted file]
drivers/net/ethernet/i825xx/82596.c
drivers/net/ethernet/i825xx/Kconfig
drivers/net/ethernet/i825xx/Makefile
drivers/net/ethernet/i825xx/eepro.c [deleted file]
drivers/net/ethernet/i825xx/eexpress.c [deleted file]
drivers/net/ethernet/i825xx/eexpress.h [deleted file]
drivers/net/ethernet/i825xx/lp486e.c [deleted file]
drivers/net/ethernet/i825xx/ni52.c [deleted file]
drivers/net/ethernet/i825xx/ni52.h [deleted file]
drivers/net/ethernet/i825xx/znet.c [deleted file]
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/Kconfig
drivers/net/ethernet/intel/e100.c
drivers/net/ethernet/intel/e1000/e1000_main.c
drivers/net/ethernet/intel/e1000e/80003es2lan.c
drivers/net/ethernet/intel/e1000e/82571.c
drivers/net/ethernet/intel/e1000e/Makefile
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/mac.c
drivers/net/ethernet/intel/e1000e/manage.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/e1000e/nvm.c
drivers/net/ethernet/intel/e1000e/param.c
drivers/net/ethernet/intel/e1000e/phy.c
drivers/net/ethernet/intel/e1000e/ptp.c [new file with mode: 0644]
drivers/net/ethernet/intel/igb/Makefile
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_82575.h
drivers/net/ethernet/intel/igb/e1000_defines.h
drivers/net/ethernet/intel/igb/e1000_hw.h
drivers/net/ethernet/intel/igb/e1000_i210.c
drivers/net/ethernet/intel/igb/e1000_i210.h
drivers/net/ethernet/intel/igb/e1000_mac.c
drivers/net/ethernet/intel/igb/e1000_mac.h
drivers/net/ethernet/intel/igb/e1000_mbx.c
drivers/net/ethernet/intel/igb/e1000_mbx.h
drivers/net/ethernet/intel/igb/e1000_nvm.c
drivers/net/ethernet/intel/igb/e1000_nvm.h
drivers/net/ethernet/intel/igb/e1000_phy.c
drivers/net/ethernet/intel/igb/e1000_phy.h
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_hwmon.c [new file with mode: 0644]
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igb/igb_ptp.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
drivers/net/ethernet/intel/ixgbevf/ethtool.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/korina.c
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/micrel/ks8842.c
drivers/net/ethernet/micrel/ks8851.c
drivers/net/ethernet/micrel/ks8851_mll.c
drivers/net/ethernet/microchip/enc28j60.c
drivers/net/ethernet/natsemi/ibmlana.c [deleted file]
drivers/net/ethernet/natsemi/ibmlana.h [deleted file]
drivers/net/ethernet/natsemi/natsemi.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
drivers/net/ethernet/neterion/vxge/vxge-main.c
drivers/net/ethernet/nuvoton/w90p910_ether.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/octeon/octeon_mgmt.c
drivers/net/ethernet/packetengines/hamachi.c
drivers/net/ethernet/packetengines/yellowfin.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/qlogic/qlcnic/Makefile
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c [new file with mode: 0644]
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h [new file with mode: 0644]
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c [new file with mode: 0644]
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c [new file with mode: 0644]
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h [new file with mode: 0644]
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/racal/Kconfig [deleted file]
drivers/net/ethernet/racal/Makefile [deleted file]
drivers/net/ethernet/racal/ni5010.c [deleted file]
drivers/net/ethernet/racal/ni5010.h [deleted file]
drivers/net/ethernet/rdc/r6040.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/s6gmac.c
drivers/net/ethernet/seeq/Kconfig
drivers/net/ethernet/seeq/Makefile
drivers/net/ethernet/seeq/seeq8005.c [deleted file]
drivers/net/ethernet/seeq/seeq8005.h [deleted file]
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/sgi/ioc3-eth.c
drivers/net/ethernet/silan/sc92031.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/smsc/smsc9420.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sunbmac.c
drivers/net/ethernet/sun/sunqe.c
drivers/net/ethernet/sun/sunvnet.c
drivers/net/ethernet/tehuti/tehuti.c
drivers/net/ethernet/ti/cpmac.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_cpdma.h
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/tile/tilepro.c
drivers/net/ethernet/toshiba/ps3_gelic_net.c
drivers/net/ethernet/toshiba/spider_net_ethtool.c
drivers/net/ethernet/toshiba/tc35815.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/wiznet/w5100.c
drivers/net/ethernet/wiznet/w5300.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/ethernet/xircom/xirc2ps_cs.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/ieee802154/fakehard.c
drivers/net/ifb.c
drivers/net/macvlan.c
drivers/net/macvtap.c
drivers/net/netconsole.c
drivers/net/phy/micrel.c
drivers/net/phy/phy_device.c
drivers/net/phy/realtek.c
drivers/net/rionet.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/asix.h
drivers/net/usb/asix_common.c
drivers/net/usb/asix_devices.c
drivers/net/usb/ax88172a.c
drivers/net/usb/catc.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/dm9601.c
drivers/net/usb/kalmia.c
drivers/net/usb/pegasus.c
drivers/net/usb/rndis_host.c
drivers/net/usb/rtl8150.c
drivers/net/usb/sierra_net.c
drivers/net/usb/smsc95xx.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/wimax/i2400m/fw.c
drivers/net/wimax/i2400m/netdev.c
drivers/net/wimax/i2400m/usb.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_initvals.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9001_initvals.h
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9340_initvals.h
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/fwcmd.h
drivers/net/wireless/ath/carl9170/hw.h
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/ath/carl9170/version.h
drivers/net/wireless/ath/regd.c
drivers/net/wireless/ath/regd.h
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/scb.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/dvm/commands.h
drivers/net/wireless/iwlwifi/dvm/debugfs.c
drivers/net/wireless/iwlwifi/dvm/led.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/tt.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-test.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/cfg.h
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/11n.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/pcie.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/util.h
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/regd.c
drivers/net/wireless/rtlwifi/regd.h
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/wlcore_i.h
drivers/net/xen-netback/interface.c
drivers/nfc/Kconfig
drivers/nfc/Makefile
drivers/nfc/nfcwilink.c
drivers/nfc/pn533.c
drivers/nfc/pn544/Kconfig [new file with mode: 0644]
drivers/nfc/pn544/Makefile
drivers/nfc/pn544/i2c.c
drivers/nfc/pn544/pn544.c
drivers/of/of_mdio.c
drivers/s390/net/Kconfig
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_mpc.c
drivers/s390/net/qeth_core_mpc.h
drivers/s390/net/qeth_core_sys.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/ssb/Kconfig
drivers/ssb/Makefile
drivers/ssb/driver_chipcommon_sflash.c [new file with mode: 0644]
drivers/ssb/driver_mipscore.c
drivers/ssb/ssb_private.h
drivers/staging/bcm/Bcmnet.c
drivers/staging/ccg/u_ether.c
drivers/staging/et131x/et131x.c
drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
drivers/staging/octeon/ethernet-mdio.c
drivers/staging/octeon/ethernet.c
drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
drivers/staging/wlags49_h2/wl_netdev.c
drivers/usb/gadget/u_ether.c
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/bcma/bcma_driver_mips.h
include/linux/bcma/bcma_driver_pci.h
include/linux/can/dev.h
include/linux/can/led.h [new file with mode: 0644]
include/linux/can/skb.h [new file with mode: 0644]
include/linux/etherdevice.h
include/linux/ieee80211.h
include/linux/in6.h
include/linux/inetdevice.h
include/linux/ipv6.h
include/linux/micrel_phy.h
include/linux/mroute.h
include/linux/mroute6.h
include/linux/netdevice.h
include/linux/netfilter/nf_conntrack_sip.h
include/linux/netpoll.h
include/linux/phy.h
include/linux/random.h
include/linux/skbuff.h
include/net/act_api.h
include/net/addrconf.h
include/net/cfg80211.h
include/net/dn_route.h
include/net/dsfield.h
include/net/gro_cells.h
include/net/inet6_hashtables.h
include/net/inet_frag.h
include/net/inet_hashtables.h
include/net/ip6_checksum.h
include/net/ip6_fib.h
include/net/ip6_route.h
include/net/ipv6.h
include/net/mac80211.h
include/net/ndisc.h
include/net/neighbour.h
include/net/netevent.h
include/net/netfilter/nf_conntrack_acct.h
include/net/netfilter/nf_conntrack_core.h
include/net/netfilter/nf_conntrack_ecache.h
include/net/netfilter/nf_conntrack_expect.h
include/net/netfilter/nf_conntrack_extend.h
include/net/netfilter/nf_conntrack_helper.h
include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_conntrack_l4proto.h
include/net/netfilter/nf_conntrack_labels.h [new file with mode: 0644]
include/net/netfilter/nf_conntrack_timeout.h
include/net/netfilter/nf_conntrack_timestamp.h
include/net/netfilter/nf_tproxy_core.h
include/net/netns/conntrack.h
include/net/netns/ipv4.h
include/net/nfc/hci.h
include/net/nfc/nci_core.h
include/net/nfc/nfc.h
include/net/pkt_cls.h
include/net/regulatory.h
include/net/sch_generic.h
include/net/sock.h
include/net/tcp.h
include/net/xfrm.h
include/uapi/asm-generic/socket.h
include/uapi/linux/can/gw.h
include/uapi/linux/if_link.h
include/uapi/linux/in6.h
include/uapi/linux/ipv6.h
include/uapi/linux/mroute.h
include/uapi/linux/mroute6.h
include/uapi/linux/netfilter/Kbuild
include/uapi/linux/netfilter/nf_conntrack_common.h
include/uapi/linux/netfilter/nfnetlink_conntrack.h
include/uapi/linux/netfilter/xt_bpf.h [new file with mode: 0644]
include/uapi/linux/netfilter/xt_connlabel.h [new file with mode: 0644]
include/uapi/linux/nfc.h
include/uapi/linux/nl80211.h
include/uapi/linux/snmp.h
include/uapi/linux/virtio_net.h
kernel/softirq.c
net/8021q/vlan.c
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/Kconfig
net/batman-adv/bat_algo.h
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bitarray.c
net/batman-adv/bitarray.h
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/bridge_loop_avoidance.h
net/batman-adv/debugfs.c
net/batman-adv/debugfs.h
net/batman-adv/distributed-arp-table.c
net/batman-adv/distributed-arp-table.h
net/batman-adv/gateway_client.c
net/batman-adv/gateway_client.h
net/batman-adv/gateway_common.c
net/batman-adv/gateway_common.h
net/batman-adv/hard-interface.c
net/batman-adv/hard-interface.h
net/batman-adv/hash.c
net/batman-adv/hash.h
net/batman-adv/icmp_socket.c
net/batman-adv/icmp_socket.h
net/batman-adv/main.c
net/batman-adv/main.h
net/batman-adv/originator.c
net/batman-adv/originator.h
net/batman-adv/packet.h
net/batman-adv/ring_buffer.c
net/batman-adv/ring_buffer.h
net/batman-adv/routing.c
net/batman-adv/routing.h
net/batman-adv/send.c
net/batman-adv/send.h
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.h
net/batman-adv/sysfs.c
net/batman-adv/sysfs.h
net/batman-adv/translation-table.c
net/batman-adv/translation-table.h
net/batman-adv/types.h
net/batman-adv/unicast.c
net/batman-adv/unicast.h
net/batman-adv/vis.c
net/batman-adv/vis.h
net/bridge/br_device.c
net/bridge/br_if.c
net/bridge/br_netlink.c
net/bridge/br_notify.c
net/bridge/br_stp_if.c
net/can/Kconfig
net/can/bcm.c
net/can/gw.c
net/can/raw.c
net/core/dev.c
net/core/ethtool.c
net/core/filter.c
net/core/flow.c
net/core/flow_dissector.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/netpoll.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/decnet/af_decnet.c
net/decnet/dn_nsp_out.c
net/decnet/dn_route.c
net/dsa/dsa.c
net/dsa/slave.c
net/ethernet/eth.c
net/ieee802154/6lowpan.c
net/ipv4/af_inet.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_fragment.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_fragment.c
net/ipv4/ip_gre.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/datagram.c
net/ipv6/exthdrs.c
net/ipv6/inet6_connection_sock.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_checksum.c [new file with mode: 0644]
net/ipv6/ip6_gre.c
net/ipv6/ip6_input.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_tunnel.c
net/irda/irnet/irnet_ppp.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/nf_conntrack_acct.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_labels.c [new file with mode: 0644]
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_udplite.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_conntrack_snmp.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_conntrack_timeout.c
net/netfilter/nf_conntrack_timestamp.c
net/netfilter/nf_nat_sip.c
net/netfilter/xt_bpf.c [new file with mode: 0644]
net/netfilter/xt_connlabel.c [new file with mode: 0644]
net/netlink/af_netlink.c
net/nfc/core.c
net/nfc/hci/command.c
net/nfc/hci/core.c
net/nfc/hci/hcp.c
net/nfc/llcp/commands.c
net/nfc/llcp/llcp.c
net/nfc/llcp/llcp.h
net/nfc/llcp/sock.c
net/nfc/nci/core.c
net/nfc/netlink.c
net/openvswitch/datapath.c
net/openvswitch/vport-internal_dev.c
net/rxrpc/af_rxrpc.c
net/sched/act_api.c
net/sched/act_csum.c
net/sched/act_gact.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/cls_api.c
net/sched/cls_basic.c
net/sched/cls_cgroup.c
net/sched/cls_flow.c
net/sched/cls_fw.c
net/sched/cls_route.c
net/sched/cls_rsvp.h
net/sched/cls_tcindex.c
net/sched/cls_u32.c
net/sctp/protocol.c
net/unix/af_unix.c
net/wireless/ap.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ethtool.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/reg.h
net/wireless/sme.c
net/wireless/util.c
net/xfrm/xfrm_algo.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_proc.c
net/xfrm/xfrm_state.c

index 2cc3c7733a2f163d9a4b871212a6c782bc5ccb95..258d9b92c36f78780fdb7f04e767158192361258 100644 (file)
@@ -52,8 +52,6 @@ de4x5.txt
        - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
 decnet.txt
        - info on using the DECnet networking layer in Linux.
-depca.txt
-       - the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver
 dl2k.txt
        - README for D-Link DL2000-based Gigabit Ethernet Adapters (dl2k.ko).
 dm9000.txt
@@ -72,8 +70,6 @@ e1000e.txt
        - README for the Intel Gigabit Ethernet Driver (e1000e).
 eql.txt
        - serial IP load balancing
-ewrk3.txt
-       - the Digital EtherWORKS 3 DE203/4/5 Ethernet driver
 fib_trie.txt
        - Level Compressed Trie (LC-trie) notes: a structure for routing.
 filter.txt
@@ -126,8 +122,6 @@ ltpc.txt
        - the Apple or Farallon LocalTalk PC card driver
 mac80211-injection.txt
        - HOWTO use packet injection with mac80211
-multicast.txt
-       - Behaviour of cards under Multicast
 multiqueue.txt
        - HOWTO for multiqueue network device support.
 netconsole.txt
diff --git a/Documentation/networking/DLINK.txt b/Documentation/networking/DLINK.txt
deleted file mode 100644 (file)
index 55d2443..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-Released 1994-06-13
-
-
-       CONTENTS:
-
-       1. Introduction.
-       2. License.
-       3. Files in this release.
-       4. Installation.
-       5. Problems and tuning.
-       6. Using the drivers with earlier releases.
-       7. Acknowledgments.
-
-
-       1. INTRODUCTION.
-
-       This is a set of Ethernet drivers for the D-Link DE-600/DE-620
-       pocket adapters, for the parallel port on a Linux based machine.
-       Some adapter "clones" will also work.  Xircom is _not_ a clone...
-       These drivers _can_ be used as loadable modules,
-       and were developed for use on Linux 1.1.13 and above.
-       For use on Linux 1.0.X, or earlier releases, see below.
-
-       I have used these drivers for NFS, ftp, telnet and X-clients on
-       remote machines. Transmissions with ftp seems to work as
-       good as can be expected (i.e. > 80k bytes/sec) from a
-       parallel port...:-)  Receive speeds will be about 60-80% of this.
-       Depending on your machine, somewhat higher speeds can be achieved.
-
-       All comments/fixes to Bjorn Ekwall (bj0rn@blox.se).
-
-
-       2. LICENSE.
-
-       This program is free software; you can redistribute it
-       and/or modify it under the terms of the GNU General Public
-       License as published by the Free Software Foundation; either
-       version 2, or (at your option) any later version.
-
-       This program is distributed in the hope that it will be
-       useful, but WITHOUT ANY WARRANTY; without even the implied
-       warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-       PURPOSE. See the GNU General Public License for more
-       details.
-
-       You should have received a copy of the GNU General Public
-       License along with this program; if not, write to the Free
-       Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
-       02139, USA.
-
-
-       3. FILES IN THIS RELEASE.
-
-       README.DLINK  This file.
-       de600.c       The Source (may it be with You :-) for the DE-600
-       de620.c       ditto for the DE-620
-       de620.h       Macros for de620.c
-
-       If you are upgrading from the d-link tar release, there will
-       also be a "dlink-patches" file that will patch Linux 1.1.18:
-               linux/drivers/net/Makefile
-               linux/drivers/net/CONFIG
-               linux/drivers/net/MODULES
-               linux/drivers/net/Space.c
-               linux/config.in
-       Apply the patch by:
-       "cd /usr/src; patch -p0 < linux/drivers/net/dlink-patches"
-       The old source, "linux/drivers/net/d_link.c", can be removed.
-
-
-       4. INSTALLATION.
-
-       o Get the latest net binaries, according to current net.wisdom.
-
-       o Read the NET-2 and Ethernet HOWTOs and modify your setup.
-
-       o If your parallel port has a strange address or irq,
-         modify "linux/drivers/net/CONFIG" accordingly, or adjust
-         the parameters in the "tuning" section in the sources.
-
-       If you are going to use the drivers as loadable modules, do _not_
-       enable them while doing "make config", but instead make sure that
-       the drivers are included in "linux/drivers/net/MODULES".
-
-       If you are _not_ going to use the driver(s) as loadable modules,
-       but instead have them included in the kernel, remember to enable
-       the drivers while doing "make config".
-
-       o To include networking and DE600/DE620 support in your kernel:
-         # cd /linux
-         (as modules:)
-         #  make config (answer yes on CONFIG_NET and CONFIG_INET)
-         (else included in the kernel:)
-         #  make config (answer yes on CONFIG _NET, _INET and _DE600 or _DE620)
-         # make clean
-         # make zImage (or whatever magic you usually do)
-
-       o I use lilo to boot multiple kernels, so that I at least
-         can have one working kernel :-). If you do too, append
-         these lines to /etc/lilo/config:
-
-               image = /linux/zImage
-               label = newlinux
-               root = /dev/hda2 (or whatever YOU have...)
-
-         # /etc/lilo/install
-
-       o Do "sync" and reboot the new kernel with a D-Link
-         DE-600/DE-620 pocket adapter connected.
-
-       o The adapter can be configured with ifconfig eth?
-         where the actual number is decided by the kernel
-         when the drivers are initialized.
-
-
-       5. "PROBLEMS" AND TUNING,
-
-       o If you see error messages from the driver, and if the traffic
-         stops on the adapter, try to do "ifconfig" and "route" once
-         more, just as in "rc.inet1".  This should take care of most
-         problems, including effects from power loss, or adapters that
-         aren't connected to the printer port in some way or another.
-         You can somewhat change the behaviour by enabling/disabling
-         the macro  SHUTDOWN_WHEN_LOST  in the "tuning" section.
-         For the DE-600 there is another macro, CHECK_LOST_DE600,
-         that you might want to read about in the "tuning" section.
-
-       o Some machines have trouble handling the parallel port and
-         the adapter at high speed. If you experience problems:
-
-         DE-600:
-         - The adapter is not recognized at boot, i.e. an Ethernet
-           address of 00:80:c8:... is not shown, try to add another
-             "; SLOW_DOWN_IO"
-           at DE600_SLOW_DOWN in the "tuning" section. As a last resort,
-           uncomment: "#define REALLY_SLOW_IO" (see <asm/io.h> for hints).
-
-         - You experience "timeout" messages: first try to add another
-             "; SLOW_DOWN_IO"
-           at DE600_SLOW_DOWN in the "tuning" section, _then_ try to
-           increase the value (original value: 5) at
-           "if (tickssofar < 5)" near line 422.
-
-         DE-620:
-         - Your parallel port might be "sluggish".  To cater for
-           this, there are the macros LOWSPEED and READ_DELAY/WRITE_DELAY
-           in the "tuning" section. Your first step should be to enable
-           LOWSPEED, and after that you can "tune" the XXX_DELAY values.
-
-       o If the adapter _is_ recognized at boot but you get messages
-         about "Network Unreachable", then the problem is probably
-         _not_ with the driver.  Check your net configuration instead
-         (ifconfig and route) in "rc.inet1".
-
-       o There is some rudimentary support for debugging, look at
-         the source. Use "-DDE600_DEBUG=3" or "-DDE620_DEBUG=3"
-         when compiling, or include it in "linux/drivers/net/CONFIG".
-         IF YOU HAVE PROBLEMS YOU CAN'T SOLVE: PLEASE COMPILE THE DRIVER
-         WITH DEBUGGING ENABLED, AND SEND ME THE RESULTING OUTPUT!
-
-
-       6. USING THE DRIVERS WITH EARLIER RELEASES.
-
-       The later 1.1.X releases of the Linux kernel include some
-       changes in the networking layer (a.k.a. NET3). This affects
-       these drivers in a few places.  The hints that follow are
-       _not_ tested by me, since I don't have the disk space to keep
-       all releases on-line.
-       Known needed changes to date:
-       - release patchfile: some patches will fail, but they should
-         be easy to apply "by hand", since they are trivial.
-         (Space.c: d_link_init() is now called de600_probe())
-       - de600.c: change  "mark_bh(NET_BH)" to  "mark_bh(INET_BH)".
-       - de620.c: (maybe) change the code around "netif_rx(skb);" to be
-                  similar to the code around "dev_rint(...)" in de600.c
-
-
-       7. ACKNOWLEDGMENTS.
-
-       These drivers wouldn't have been done without the base
-       (and support) from Ross Biro, and D-Link Systems Inc.
-       The driver relies upon GPL-ed source from D-Link Systems Inc.
-       and from Russel Nelson at Crynwr Software <nelson@crynwr.com>.
-
-       Additional input also from:
-       Donald Becker <becker@super.org>, Alan Cox <A.Cox@swansea.ac.uk>
-       and Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
-
-       DE-600 alpha release primary victim^H^H^H^H^H^Htester:
-       - Erik Proper <erikp@cs.kun.nl>.
-       Good input also from several users, most notably
-       - Mark Burton <markb@ordern.demon.co.uk>.
-
-       DE-620 alpha release victims^H^H^H^H^H^H^Htesters:
-       - J. Joshua Kopper <kopper@rtsg.mot.com>
-       - Olav Kvittem <Olav.Kvittem@uninett.no>
-       - Germano Caronni <caronni@nessie.cs.id.ethz.ch>
-       - Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
-
-
-       Happy hacking!
-
-       Bjorn Ekwall == bj0rn@blox.se
index c725d33b316fbadebb0d93d1fb70c193318ac1a2..0e190180eec88ae1ca3fee9174512e0baa07b032 100644 (file)
@@ -36,7 +36,6 @@ TABLE OF CONTENTS
     4.1 Compiling the Driver as a Loadable Module
     4.2 Compiling the driver to support memory mode
     4.3 Compiling the driver to support Rx DMA 
-    4.4 Compiling the Driver into the Kernel
 
 5.0 TESTING AND TROUBLESHOOTING
     5.1 Known Defects and Limitations
@@ -364,84 +363,6 @@ The compile-time optionality for DMA was removed in the 2.3 kernel
 series.  DMA support is now unconditionally part of the driver.  It is
 enabled by the 'use_dma=1' module option.
 
-4.4 COMPILING THE DRIVER INTO THE KERNEL
-
-If your Linux distribution already has support for the cs89x0 driver
-then simply copy the source file to the /usr/src/linux/drivers/net
-directory to replace the original ones and run the make utility to
-rebuild the kernel.  See Step 3 for rebuilding the kernel.
-
-If your Linux does not include the cs89x0 driver, you need to edit three 
-configuration files, copy the source file to the /usr/src/linux/drivers/net
-directory, and then run the make utility to rebuild the kernel.
-
-1. Edit the following configuration files by adding the statements as
-indicated.  (When possible, try to locate the added text to the section of the
-file containing similar statements).
-
-
-a.) In /usr/src/linux/drivers/net/Config.in, add:
-
-tristate 'CS89x0 support' CONFIG_CS89x0
-
-Example:
-
-     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
-     fi
-
-     tristate 'CS89x0 support' CONFIG_CS89x0
-
-     tristate 'NE2000/NE1000 support' CONFIG_NE2000
-     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-       tristate 'NI5210 support' CONFIG_NI52
-
-
-b.) In /usr/src/linux/drivers/net/Makefile, add the following lines: 
-
-ifeq ($(CONFIG_CS89x0),y)
-L_OBJS += cs89x0.o
-else
-  ifeq ($(CONFIG_CS89x0),m)
-  M_OBJS += cs89x0.o
-  endif
-endif
-
-
-c.) In /linux/drivers/net/Space.c file, add the line:
-
-extern int cs89x0_probe(struct device *dev);
-
-
-Example:
-
- extern int ultra_probe(struct device *dev);
- extern int wd_probe(struct device *dev);
- extern int el2_probe(struct device *dev);
-
- extern int cs89x0_probe(struct device *dev);
-
- extern int ne_probe(struct device *dev);
- extern int hp_probe(struct device *dev);
- extern int hp_plus_probe(struct device *dev);
-
-
-Also add:
-
- #ifdef CONFIG_CS89x0
-       { cs89x0_probe,0 },
- #endif
-
-
-2.) Copy the driver source files (cs89x0.c and cs89x0.h) 
-into the /usr/src/linux/drivers/net directory.
-
-
-3.) Go to /usr/src/linux directory and run 'make config' followed by 'make' 
-(or make bzImage) to rebuild the kernel. 
-
-4.) Use the DOS 'setup' utility to disable plug and play on the NIC.
-
 
 5.0 TESTING AND TROUBLESHOOTING
 ===============================================================================
diff --git a/Documentation/networking/depca.txt b/Documentation/networking/depca.txt
deleted file mode 100644 (file)
index 24c6b26..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-
-DE10x
-=====
-
-Memory Addresses:
-
-       SW1     SW2     SW3     SW4
-64K    on      on      on      on      d0000   dbfff
-       off     on      on      on      c0000   cbfff
-       off     off     on      on      e0000   ebfff
-
-32K    on      on      off     on      d8000   dbfff
-       off     on      off     on      c8000   cbfff
-       off     off     off     on      e8000   ebfff
-
-DBR ROM        on      on                      dc000   dffff
-       off     on                      cc000   cffff
-       off     off                     ec000   effff
-
-Note  that the 2K  mode   is set  by   SW3/SW4  on/off or  off/off.  Address
-assignment is through the RBSA register.
-
-I/O Address:
-       SW5
-0x300  on
-0x200  off
-
-Remote Boot:
-       SW6
-Disable        on
-Enable off
-
-Remote Boot Timeout:
-       SW7
-2.5min on
-30s    off
-
-IRQ:
-       SW8     SW9     SW10    SW11    SW12
-2      on      off     off     off     off
-3      off     on      off     off     off
-4      off     off     on      off     off
-5      off     off     off     on      off
-7      off     off     off     off     on
-
-DE20x
-=====
-
-Memory Size:
-
-       SW3     SW4
-64K    on      on
-32K    off     on
-2K     on      off
-2K     off     off
-
-Start Addresses:
-
-       SW1     SW2     SW3     SW4
-64K    on      on      on      on      c0000   cffff
-       on      off     on      on      d0000   dffff
-       off     on      on      on      e0000   effff
-
-32K    on      on      off     off     c8000   cffff
-       on      off     off     off     d8000   dffff
-       off     on      off     off     e8000   effff
-
-Illegal        off     off      -       -        -       -
-
-I/O Address:
-       SW5
-0x300  on
-0x200  off
-
-Remote Boot:
-       SW6
-Disable        on
-Enable off
-
-Remote Boot Timeout:
-       SW7
-2.5min on
-30s    off
-
-IRQ:
-       SW8     SW9     SW10    SW11    SW12
-5      on      off     off     off     off
-9      off     on      off     off     off
-10     off     off     on      off     off
-11     off     off     off     on      off
-15     off     off     off     off     on
-
diff --git a/Documentation/networking/ewrk3.txt b/Documentation/networking/ewrk3.txt
deleted file mode 100644 (file)
index 90e9e5f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-The EtherWORKS 3  driver in this distribution is  designed to  work with all
-kernels   >  1.1.33   (approx)  and  includes  tools   in  the  'ewrk3tools'
-subdirectory   to  allow  set   up of   the   card,  similar  to  the  MSDOS
-'NICSETUP.EXE' tools provided on  the DOS drivers  disk (type 'make' in that
-subdirectory to make the tools).
-
-The supported  cards are DE203,  DE204 and DE205.  All   other cards are NOT
-supported - refer to 'depca.c' for running the LANCE based network cards and
-'de4x5.c'  for the  DIGITAL   Semiconductor PCI  chip  based  adapters  from
-Digital.
-
-The ability to load  this driver as a  loadable module has been included and
-used extensively  during the driver  development (to save those  long reboot
-sequences). To utilise this ability, you have to do 8 things:
-
-    0) have a copy of the loadable modules code installed on your system.
-    1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
-    temporary directory.
-    2) edit the  source code near  line 1898 to reflect  the I/O address and
-    IRQ you're using.
-    3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
-    that the correct bits are compiled (see end of source code).
-    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
-    kernel with the ewrk3 configuration turned off and reboot.
-    5) insmod ewrk3.o
-          [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
-          [Adam Kropelin: Multiple cards now supported by irq=x1,x2 io=y1,y2]
-    6) run the net startup bits for your new eth?? interface manually 
-    (usually /etc/rc.inet[12] at boot time). 
-    7) enjoy!
-
-    Note that autoprobing is not allowed in loadable modules - the system is
-    already up and running and you're messing with interrupts.
-
-    To unload a module, turn off the associated interface 
-    'ifconfig eth?? down' then 'rmmod ewrk3'.
-
-The performance we've  achieved so far  has been measured through the 'ttcp'
-tool   at 975kB/s.  This  measures  the  total  TCP  stack performance which
-includes the   card,  so don't  expect   to get   much nearer  the  1.25MB/s
-theoretical Ethernet rate.
-
-
-Enjoy!
-
-Dave
index bbf2005270b5d1c1d3e0ffeb44a1082b8c0b8d75..cdb3e40b9d14ee28095fb02a088154a8989996c4 100644 (file)
@@ -17,12 +17,12 @@ creating filters.
 
 LSF is much simpler than BPF. One does not have to worry about
 devices or anything like that. You simply create your filter
-code, send it to the kernel via the SO_ATTACH_FILTER ioctl and
+code, send it to the kernel via the SO_ATTACH_FILTER option and
 if your filter code passes the kernel check on it, you then
 immediately begin filtering data on that socket.
 
 You can also detach filters from your socket via the
-SO_DETACH_FILTER ioctl. This will probably not be used much
+SO_DETACH_FILTER option. This will probably not be used much
 since when you close a socket that has a filter on it the
 filter is automagically removed. The other less common case
 may be adding a different filter on the same socket where you had another
@@ -31,12 +31,19 @@ the old one and placing your new one in its place, assuming your
 filter has passed the checks, otherwise if it fails the old filter
 will remain on that socket.
 
+SO_LOCK_FILTER option allows to lock the filter attached to a
+socket. Once set, a filter cannot be removed or changed. This allows
+one process to setup a socket, attach a filter, lock it then drop
+privileges and be assured that the filter will be kept until the
+socket is closed.
+
 Examples
 ========
 
 Ioctls-
 setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter));
 setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &value, sizeof(value));
+setsockopt(sockfd, SOL_SOCKET, SO_LOCK_FILTER, &value, sizeof(value));
 
 See the BSD bpf.4 manpage and the BSD Packet Filter paper written by
 Steven McCanne and Van Jacobson of Lawrence Berkeley Laboratory.
index dbca6618208935505c00d193abccbe8e63962eee..19ac1802bfd4d04a456b6934322d75b89cd1ea17 100644 (file)
@@ -26,6 +26,11 @@ route/max_size - INTEGER
        Maximum number of routes allowed in the kernel.  Increase
        this when using large numbers of interfaces and/or routes.
 
+neigh/default/gc_thresh1 - INTEGER
+       Minimum number of entries to keep.  Garbage collector will not
+       purge entries if there are fewer than this number.
+       Default: 256
+
 neigh/default/gc_thresh3 - INTEGER
        Maximum number of neighbor entries allowed.  Increase this
        when using large numbers of interfaces and when communicating
@@ -214,7 +219,8 @@ tcp_ecn - INTEGER
        congestion before having to drop packets.
        Possible values are:
                0 Disable ECN.  Neither initiate nor accept ECN.
-               1 Always request ECN on outgoing connection attempts.
+               1 Enable ECN when requested by incoming connections and
+                 also request ECN on outgoing connection attempts.
                2 Enable ECN when requested by incoming connections
                  but do not request ECN on outgoing connections.
        Default: 2
diff --git a/Documentation/networking/multicast.txt b/Documentation/networking/multicast.txt
deleted file mode 100644 (file)
index b06c8c6..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-Behaviour of Cards Under Multicast
-==================================
-
-This is how they currently behave, not what the hardware can do--for example,
-the Lance driver doesn't use its filter, even though the code for loading
-it is in the DEC Lance-based driver.
-
-The following are requirements for multicasting 
------------------------------------------------
-AppleTalk      Multicast       hardware filtering not important but
-                                avoid cards only doing promisc
-IP-Multicast   Multicast       hardware filters really help
-IP-MRoute      AllMulti        hardware filters are of no help
-
-
-Board          Multicast       AllMulti        Promisc         Filter
-------------------------------------------------------------------------
-3c501          YES             YES             YES             Software
-3c503          YES             YES             YES             Hardware
-3c505          YES             NO              YES             Hardware
-3c507          NO              NO              NO              N/A
-3c509          YES             YES             YES             Software
-3c59x          YES             YES             YES             Software
-ac3200         YES             YES             YES             Hardware
-apricot                YES             PROMISC         YES             Hardware
-arcnet         NO              NO              NO              N/A
-at1700         PROMISC         PROMISC         YES             Software
-atp            PROMISC         PROMISC         YES             Software
-cs89x0         YES             YES             YES             Software
-de4x5          YES             YES             YES             Hardware
-de600          NO              NO              NO              N/A
-de620          PROMISC         PROMISC         YES             Software
-depca          YES             PROMISC         YES             Hardware
-dmfe           YES             YES             YES             Software(*)
-e2100          YES             YES             YES             Hardware
-eepro          YES             PROMISC         YES             Hardware
-eexpress       NO              NO              NO              N/A
-ewrk3          YES             PROMISC         YES             Hardware
-hp-plus                YES             YES             YES             Hardware
-hp             YES             YES             YES             Hardware
-hp100          YES             YES             YES             Hardware
-ibmtr          NO              NO              NO              N/A
-ioc3-eth       YES             YES             YES             Hardware
-lance          YES             YES             YES             Software(#)
-ne             YES             YES             YES             Hardware
-ni52           <------------------ Buggy ------------------>
-ni65           YES             YES             YES             Software(#)
-seeq           NO              NO              NO              N/A
-sgiseek                <------------------ Buggy ------------------>
-smc-ultra      YES             YES             YES             Hardware
-sunlance       YES             YES             YES             Hardware
-tulip          YES             YES             YES             Hardware
-wavelan                YES             PROMISC         YES             Hardware
-wd             YES             YES             YES             Hardware
-xirc2ps_cs     YES             YES             YES             Hardware
-znet           YES             YES             YES             Software
-
-
-PROMISC = This multicast mode is in fact promiscuous mode. Avoid using
-cards who go PROMISC on any multicast in a multicast kernel.
-
-(#) = Hardware multicast support is not used yet.
-(*) = Hardware support for Davicom 9132 chipset only.
index 2e9e0ae2cd453dc3ac0a605c1a40baf1096cf42f..a5d574a9ae0987031b408671a5808356f6955cb4 100644 (file)
@@ -1,9 +1,10 @@
 
 started by Ingo Molnar <mingo@redhat.com>, 2001.09.17
 2.6 port and netpoll api by Matt Mackall <mpm@selenic.com>, Sep 9 2003
+IPv6 support by Cong Wang <xiyou.wangcong@gmail.com>, Jan 1 2013
 
 Please send bug reports to Matt Mackall <mpm@selenic.com>
-and Satyam Sharma <satyam.sharma@gmail.com>
+Satyam Sharma <satyam.sharma@gmail.com>, and Cong Wang <xiyou.wangcong@gmail.com>
 
 Introduction:
 =============
@@ -41,6 +42,10 @@ Examples:
 
  insmod netconsole netconsole=@/,@10.0.0.2/
 
+  or using IPv6
+
+ insmod netconsole netconsole=@/,@fd00:1:2:3::1/
+
 It also supports logging to multiple remote agents by specifying
 parameters for the multiple agents separated by semicolons and the
 complete string enclosed in "quotes", thusly:
diff --git a/Documentation/networking/nf_conntrack-sysctl.txt b/Documentation/networking/nf_conntrack-sysctl.txt
new file mode 100644 (file)
index 0000000..70da508
--- /dev/null
@@ -0,0 +1,176 @@
+/proc/sys/net/netfilter/nf_conntrack_* Variables:
+
+nf_conntrack_acct - BOOLEAN
+       0 - disabled (default)
+       not 0 - enabled
+
+       Enable connection tracking flow accounting. 64-bit byte and packet
+       counters per flow are added.
+
+nf_conntrack_buckets - INTEGER (read-only)
+       Size of hash table. If not specified as parameter during module
+       loading, the default size is calculated by dividing total memory
+       by 16384 to determine the number of buckets but the hash table will
+       never have fewer than 32 or more than 16384 buckets.
+
+nf_conntrack_checksum - BOOLEAN
+       0 - disabled
+       not 0 - enabled (default)
+
+       Verify checksum of incoming packets. Packets with bad checksums are
+       in INVALID state. If this is enabled, such packets will not be
+       considered for connection tracking.
+
+nf_conntrack_count - INTEGER (read-only)
+       Number of currently allocated flow entries.
+
+nf_conntrack_events - BOOLEAN
+       0 - disabled
+       not 0 - enabled (default)
+
+       If this option is enabled, the connection tracking code will
+       provide userspace with connection tracking events via ctnetlink.
+
+nf_conntrack_events_retry_timeout - INTEGER (seconds)
+       default 15
+
+       This option is only relevant when "reliable connection tracking
+       events" are used.  Normally, ctnetlink is "lossy", that is,
+       events are normally dropped when userspace listeners can't keep up.
+
+       Userspace can request "reliable event mode".  When this mode is
+       active, the conntrack will only be destroyed after the event was
+       delivered.  If event delivery fails, the kernel periodically
+       re-tries to send the event to userspace.
+
+       This is the maximum interval the kernel should use when re-trying
+       to deliver the destroy event.
+
+       A higher number means there will be fewer delivery retries and it
+       will take longer for a backlog to be processed.
+
+nf_conntrack_expect_max - INTEGER
+       Maximum size of expectation table.  Default value is
+       nf_conntrack_buckets / 256. Minimum is 1.
+
+nf_conntrack_frag6_high_thresh - INTEGER
+       default 262144
+
+       Maximum memory used to reassemble IPv6 fragments.  When
+       nf_conntrack_frag6_high_thresh bytes of memory is allocated for this
+       purpose, the fragment handler will toss packets until
+       nf_conntrack_frag6_low_thresh is reached.
+
+nf_conntrack_frag6_low_thresh - INTEGER
+       default 196608
+
+       See nf_conntrack_frag6_low_thresh
+
+nf_conntrack_frag6_timeout - INTEGER (seconds)
+       default 60
+
+       Time to keep an IPv6 fragment in memory.
+
+nf_conntrack_generic_timeout - INTEGER (seconds)
+       default 600
+
+       Default for generic timeout.  This refers to layer 4 unknown/unsupported
+       protocols.
+
+nf_conntrack_helper - BOOLEAN
+       0 - disabled
+       not 0 - enabled (default)
+
+       Enable automatic conntrack helper assignment.
+
+nf_conntrack_icmp_timeout - INTEGER (seconds)
+       default 30
+
+       Default for ICMP timeout.
+
+nf_conntrack_icmpv6_timeout - INTEGER (seconds)
+       default 30
+
+       Default for ICMP6 timeout.
+
+nf_conntrack_log_invalid - INTEGER
+       0   - disable (default)
+       1   - log ICMP packets
+       6   - log TCP packets
+       17  - log UDP packets
+       33  - log DCCP packets
+       41  - log ICMPv6 packets
+       136 - log UDPLITE packets
+       255 - log packets of any protocol
+
+       Log invalid packets of a type specified by value.
+
+nf_conntrack_max - INTEGER
+       Size of connection tracking table.  Default value is
+       nf_conntrack_buckets value * 4.
+
+nf_conntrack_tcp_be_liberal - BOOLEAN
+       0 - disabled (default)
+       not 0 - enabled
+
+       Be conservative in what you do, be liberal in what you accept from others.
+       If it's non-zero, we mark only out of window RST segments as INVALID.
+
+nf_conntrack_tcp_loose - BOOLEAN
+       0 - disabled
+       not 0 - enabled (default)
+
+       If it is set to zero, we disable picking up already established
+       connections.
+
+nf_conntrack_tcp_max_retrans - INTEGER
+       default 3
+
+       Maximum number of packets that can be retransmitted without
+       received an (acceptable) ACK from the destination. If this number
+       is reached, a shorter timer will be started.
+
+nf_conntrack_tcp_timeout_close - INTEGER (seconds)
+       default 10
+
+nf_conntrack_tcp_timeout_close_wait - INTEGER (seconds)
+       default 60
+
+nf_conntrack_tcp_timeout_established - INTEGER (seconds)
+       default 432000 (5 days)
+
+nf_conntrack_tcp_timeout_fin_wait - INTEGER (seconds)
+       default 120
+
+nf_conntrack_tcp_timeout_last_ack - INTEGER (seconds)
+       default 30
+
+nf_conntrack_tcp_timeout_max_retrans - INTEGER (seconds)
+       default 300
+
+nf_conntrack_tcp_timeout_syn_recv - INTEGER (seconds)
+       default 60
+
+nf_conntrack_tcp_timeout_syn_sent - INTEGER (seconds)
+       default 120
+
+nf_conntrack_tcp_timeout_time_wait - INTEGER (seconds)
+       default 120
+
+nf_conntrack_tcp_timeout_unacknowledged - INTEGER (seconds)
+       default 300
+
+nf_conntrack_timestamp - BOOLEAN
+       0 - disabled (default)
+       not 0 - enabled
+
+       Enable connection tracking flow timestamping.
+
+nf_conntrack_udp_timeout - INTEGER (seconds)
+       default 30
+
+nf_conntrack_udp_timeout_stream2 - INTEGER (seconds)
+       default 180
+
+       This extended timeout will be used in case there is an UDP stream
+       detected.
index 1a77a3cfae540795d1d2ae0074cde85f15113f42..97694572338be53d1cfddd03b4112e7ef6a771a8 100644 (file)
@@ -88,6 +88,10 @@ set this flag. On netif_carrier_off(), the scheduler stops sending
 packets. The name 'carrier' and the inversion are historical, think of
 it as lower layer.
 
+Note that for certain kind of soft-devices, which are not managing any
+real hardware, there is possible to set this bit from userpsace.
+One should use TVL IFLA_CARRIER to do so.
+
 netif_carrier_ok() can be used to query that bit.
 
 __LINK_STATE_DORMANT, maps to IFF_DORMANT:
index 95e5f5985a2aecaffb81081fc4594d9b5ef6c074..d5b1a393524533557a4286a3e1c92cbb50eddd50 100644 (file)
@@ -103,7 +103,7 @@ Letting the PHY Abstraction Layer do Everything
  
  Now, to connect, just call this function:
  
-   phydev = phy_connect(dev, phy_name, &adjust_link, flags, interface);
+   phydev = phy_connect(dev, phy_name, &adjust_link, interface);
 
  phydev is a pointer to the phy_device structure which represents the PHY.  If
  phy_connect is successful, it will return the pointer.  dev, here, is the
@@ -113,7 +113,9 @@ Letting the PHY Abstraction Layer do Everything
  current state, though the PHY will not yet be truly operational at this
  point.
 
- flags is a u32 which can optionally contain phy-specific flags.
+ PHY-specific flags should be set in phydev->dev_flags prior to the call
+ to phy_connect() such that the underlying PHY driver can check for flags
+ and perform specific operations based on them.
  This is useful if the system has put hardware restrictions on
  the PHY/controller, of which the PHY needs to be aware.
 
@@ -185,11 +187,10 @@ Doing it all yourself
    start, or disables then frees them for stop.
 
  struct phy_device * phy_attach(struct net_device *dev, const char *phy_id,
-                u32 flags, phy_interface_t interface);
+                phy_interface_t interface);
 
    Attaches a network device to a particular PHY, binding the PHY to a generic
-   driver if none was found during bus initialization.  Passes in
-   any phy-specific flags as needed.
+   driver if none was found during bus initialization.
 
  int phy_start_aneg(struct phy_device *phydev);
    
index 89a339c9b079160429bb43f133049e83ebfe7f4d..0686c9e211c2828526a43549a871af11ae92f3e4 100644 (file)
@@ -17,10 +17,12 @@ HCI
 HCI registers as an nfc device with NFC Core. Requests coming from userspace are
 routed through netlink sockets to NFC Core and then to HCI. From this point,
 they are translated in a sequence of HCI commands sent to the HCI layer in the
-host controller (the chip). The sending context blocks while waiting for the
-response to arrive.
+host controller (the chip). Commands can be executed synchronously (the sending
+context blocks waiting for response) or asynchronously (the response is returned
+from HCI Rx context).
 HCI events can also be received from the host controller. They will be handled
-and a translation will be forwarded to NFC Core as needed.
+and a translation will be forwarded to NFC Core as needed. There are hooks to
+let the HCI driver handle proprietary events or override standard behavior.
 HCI uses 2 execution contexts:
 - one for executing commands : nfc_hci_msg_tx_work(). Only one command
 can be executing at any given moment.
@@ -33,6 +35,8 @@ The Session initialization is an HCI standard which must unfortunately
 support proprietary gates. This is the reason why the driver will pass a list
 of proprietary gates that must be part of the session. HCI will ensure all
 those gates have pipes connected when the hci device is set up.
+In case the chip supports pre-opened gates and pseudo-static pipes, the driver
+can pass that information to HCI core.
 
 HCI Gates and Pipes
 -------------------
@@ -46,6 +50,13 @@ without knowing the pipe connected to it.
 Driver interface
 ----------------
 
+A driver is generally written in two parts : the physical link management and
+the HCI management. This makes it easier to maintain a driver for a chip that
+can be connected using various phy (i2c, spi, ...)
+
+HCI Management
+--------------
+
 A driver would normally register itself with HCI and provide the following
 entry points:
 
@@ -53,58 +64,113 @@ struct nfc_hci_ops {
        int (*open)(struct nfc_hci_dev *hdev);
        void (*close)(struct nfc_hci_dev *hdev);
        int (*hci_ready) (struct nfc_hci_dev *hdev);
-       int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
-       int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols);
-       int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate,
-                               struct nfc_target *target);
+       int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
+       int (*start_poll) (struct nfc_hci_dev *hdev,
+                          u32 im_protocols, u32 tm_protocols);
+       int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
+                          u8 comm_mode, u8 *gb, size_t gb_len);
+       int (*dep_link_down)(struct nfc_hci_dev *hdev);
+       int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
+                                struct nfc_target *target);
        int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
                                           struct nfc_target *target);
-       int (*data_exchange) (struct nfc_hci_dev *hdev,
-                             struct nfc_target *target,
-                             struct sk_buff *skb, struct sk_buff **res_skb);
+       int (*im_transceive) (struct nfc_hci_dev *hdev,
+                             struct nfc_target *target, struct sk_buff *skb,
+                             data_exchange_cb_t cb, void *cb_context);
+       int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_hci_dev *hdev,
                              struct nfc_target *target);
+       int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+                             struct sk_buff *skb);
 };
 
 - open() and close() shall turn the hardware on and off.
 - hci_ready() is an optional entry point that is called right after the hci
 session has been set up. The driver can use it to do additional initialization
 that must be performed using HCI commands.
-- xmit() shall simply write a frame to the chip.
+- xmit() shall simply write a frame to the physical link.
 - start_poll() is an optional entrypoint that shall set the hardware in polling
 mode. This must be implemented only if the hardware uses proprietary gates or a
 mechanism slightly different from the HCI standard.
+- dep_link_up() is called after a p2p target has been detected, to finish
+the p2p connection setup with hardware parameters that need to be passed back
+to nfc core.
+- dep_link_down() is called to bring the p2p link down.
 - target_from_gate() is an optional entrypoint to return the nfc protocols
 corresponding to a proprietary gate.
 - complete_target_discovered() is an optional entry point to let the driver
 perform additional proprietary processing necessary to auto activate the
 discovered target.
-- data_exchange() must be implemented by the driver if proprietary HCI commands
+- im_transceive() must be implemented by the driver if proprietary HCI commands
 are required to send data to the tag. Some tag types will require custom
 commands, others can be written to using the standard HCI commands. The driver
 can check the tag type and either do proprietary processing, or return 1 to ask
-for standard processing.
+for standard processing. The data exchange command itself must be sent
+asynchronously.
+- tm_send() is called to send data in the case of a p2p connection
 - check_presence() is an optional entry point that will be called regularly
 by the core to check that an activated tag is still in the field. If this is
 not implemented, the core will not be able to push tag_lost events to the user
 space
+- event_received() is called to handle an event coming from the chip. Driver
+can handle the event or return 1 to let HCI attempt standard processing.
 
 On the rx path, the driver is responsible to push incoming HCP frames to HCI
 using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
 This must be done from a context that can sleep.
 
-SHDLC
------
+PHY Management
+--------------
+
+The physical link (i2c, ...) management is defined by the following struture:
+
+struct nfc_phy_ops {
+       int (*write)(void *dev_id, struct sk_buff *skb);
+       int (*enable)(void *dev_id);
+       void (*disable)(void *dev_id);
+};
+
+enable(): turn the phy on (power on), make it ready to transfer data
+disable(): turn the phy off
+write(): Send a data frame to the chip. Note that to enable higher
+layers such as an llc to store the frame for re-emission, this function must
+not alter the skb. It must also not return a positive result (return 0 for
+success, negative for failure).
+
+Data coming from the chip shall be sent directly to nfc_hci_recv_frame().
+
+LLC
+---
+
+Communication between the CPU and the chip often requires some link layer
+protocol. Those are isolated as modules managed by the HCI layer. There are
+currently two modules : nop (raw transfert) and shdlc.
+A new llc must implement the following functions:
+
+struct nfc_llc_ops {
+       void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv,
+                      rcv_to_hci_t rcv_to_hci, int tx_headroom,
+                      int tx_tailroom, int *rx_headroom, int *rx_tailroom,
+                      llc_failure_t llc_failure);
+       void (*deinit) (struct nfc_llc *llc);
+       int (*start) (struct nfc_llc *llc);
+       int (*stop) (struct nfc_llc *llc);
+       void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb);
+       int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb);
+};
+
+- init() : allocate and init your private storage
+- deinit() : cleanup
+- start() : establish the logical connection
+- stop () : terminate the logical connection
+- rcv_from_drv() : handle data coming from the chip, going to HCI
+- xmit_from_hci() : handle data sent by HCI, going to the chip
 
-Most chips use shdlc to ensure integrity and delivery ordering of the HCP
-frames between the host controller (the chip) and hosts (entities connected
-to the chip, like the cpu). In order to simplify writing the driver, an shdlc
-layer is available for use by the driver.
-When used, the driver actually registers with shdlc, and shdlc will register
-with HCI. HCI sees shdlc as the driver and thus send its HCP frames
-through shdlc->xmit.
-SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state
-machine and handle both its rx and tx path.
+The llc must be registered with nfc before it can be used. Do that by
+calling nfc_llc_register(const char *name, struct nfc_llc_ops *ops);
+
+Again, note that the llc does not handle the physical link. It is thus very
+easy to mix any physical link with any llc for a given chip driver.
 
 Included Drivers
 ----------------
@@ -117,10 +183,12 @@ Execution Contexts
 
 The execution contexts are the following:
 - IRQ handler (IRQH):
-fast, cannot sleep. stores incoming frames into an shdlc rx queue
+fast, cannot sleep. sends incoming frames to HCI where they are passed to
+the current llc. In case of shdlc, the frame is queued in shdlc rx queue.
 
 - SHDLC State Machine worker (SMW)
-handles shdlc rx & tx queues. Dispatches HCI cmd responses.
+Only when llc_shdlc is used: handles shdlc rx & tx queues.
+Dispatches HCI cmd responses.
 
 - HCI Tx Cmd worker (MSGTXWQ)
 Serializes execution of HCI commands. Completes execution in case of response
@@ -166,6 +234,15 @@ waiting command execution. Response processing involves invoking the completion
 callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
 The completion callback will then wake the syscall context.
 
+It is also possible to execute the command asynchronously using this API:
+
+static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
+                              const u8 *param, size_t param_len,
+                              data_exchange_cb_t cb, void *cb_context)
+
+The workflow is the same, except that the API call returns immediately, and
+the callback will be called with the result from the SMW context.
+
 Workflow receiving an HCI event or command
 ------------------------------------------
 
index 2fcac9f5996e32386459c1c066c2447227d79a15..b36ca14ca2d65a0e974228622f6ea2cba45cdb54 100644 (file)
@@ -1,32 +1,15 @@
 Kernel driver for the NXP Semiconductors PN544 Near Field
 Communication chip
 
-Author: Jari Vanhala
-Contact: Matti Aaltonen (matti.j.aaltonen at nokia.com)
-
 General
 -------
 
 The PN544 is an integrated transmission module for contactless
 communication. The driver goes under drives/nfc/ and is compiled as a
-module named "pn544". It registers a misc device and creates a device
-file named "/dev/pn544".
+module named "pn544".
 
 Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C.
 
-The Interface
--------------
-
-The driver offers a sysfs interface for a hardware test and an IOCTL
-interface for selecting between two operating modes. There are read,
-write and poll functions for transferring messages. The two operating
-modes are the normal (HCI) mode and the firmware update mode.
-
-PN544 is controlled by sending messages from the userspace to the
-chip. The main function of the driver is just to pass those messages
-without caring about the message content.
-
-
 Protocols
 ---------
 
@@ -47,68 +30,3 @@ and third (LSB) bytes of the message. The maximum FW message length is
 
 For the ETSI HCI specification see
 http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx
-
-The Hardware Test
------------------
-
-The idea of the test is that it can performed by reading from the
-corresponding sysfs file. The test is implemented in the board file
-and it should test that PN544 can be put into the firmware update
-mode. If the test is not implemented the sysfs file does not get
-created.
-
-Example:
-> cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test
-1
-
-Normal Operation
-----------------
-
-PN544 is powered up when the device file is opened, otherwise it's
-turned off. Only one instance can use the device at a time.
-
-Userspace applications control PN544 with HCI messages. The hardware
-sends an interrupt when data is available for reading. Data is
-physically read when the read function is called by a userspace
-application. Poll() checks the read interrupt state. Configuration and
-self testing are also done from the userspace using read and write.
-
-Example platform data:
-
-static int rx71_pn544_nfc_request_resources(struct i2c_client *client)
-{
-       /* Get and setup the HW resources for the device */
-}
-
-static void rx71_pn544_nfc_free_resources(void)
-{
-       /* Release the HW resources */
-}
-
-static void rx71_pn544_nfc_enable(int fw)
-{
-       /* Turn the device on */
-}
-
-static int rx71_pn544_nfc_test(void)
-{
-       /*
-        * Put the device into the FW update mode
-        * and then back to the normal mode.
-        * Check the behavior and return one on success,
-        * zero on failure.
-        */
-}
-
-static void rx71_pn544_nfc_disable(void)
-{
-       /* turn the power off */
-}
-
-static struct pn544_nfc_platform_data rx71_nfc_data = {
-       .request_resources = rx71_pn544_nfc_request_resources,
-       .free_resources = rx71_pn544_nfc_free_resources,
-       .enable = rx71_pn544_nfc_enable,
-       .test = rx71_pn544_nfc_test,
-       .disable = rx71_pn544_nfc_disable,
-};
index 76ae4aa1512921ce0bce8be03634f70bc2c30564..b5ab4d9a48a7f3fa9cf9c13572693581e75a77df 100644 (file)
@@ -2974,11 +2974,6 @@ S:       Maintained
 F:     include/linux/netfilter_bridge/
 F:     net/bridge/
 
-ETHERTEAM 16I DRIVER
-M:     Mika Kuoppala <miku@iki.fi>
-S:     Maintained
-F:     drivers/net/ethernet/fujitsu/eth16i.c
-
 EXT2 FILE SYSTEM
 M:     Jan Kara <jack@suse.cz>
 L:     linux-ext4@vger.kernel.org
@@ -5369,13 +5364,6 @@ F:       include/linux/sunrpc/
 F:     include/uapi/linux/nfs*
 F:     include/uapi/linux/sunrpc/
 
-NI5010 NETWORK DRIVER
-M:     Jan-Pascal van Best <janpascal@vanbest.org>
-M:     Andreas Mohr <andi@lisas.de>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/racal/ni5010.*
-
 NILFS2 FILESYSTEM
 M:     KONISHI Ryusuke <konishi.ryusuke@lab.ntt.co.jp>
 L:     linux-nilfs@vger.kernel.org
index 097c1577735af85844b58ad1b4f6c71767f94d6c..c5195524d1ef8904af746889e9955271b2ff55c1 100644 (file)
@@ -19,7 +19,7 @@
 #define SO_BROADCAST   0x0020
 #define SO_LINGER      0x0080
 #define SO_OOBINLINE   0x0100
-/* To add :#define SO_REUSEPORT 0x0200 */
+#define SO_REUSEPORT   0x0200
 
 #define SO_TYPE                0x1008
 #define SO_ERROR       0x1007
@@ -77,5 +77,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
 
 #endif /* _UAPI_ASM_SOCKET_H */
index 486df68abeecc955757a352cf64e70ad9b39a020..51c6401582ea677a1d9d211ce3652b833de9516c 100644 (file)
@@ -22,7 +22,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -70,4 +70,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* __ASM_AVR32_SOCKET_H */
index b681b043f6c819fedc4b819c5ffa59a72cd7059f..50692b738c756172af61ab84f2f8693495ea6655 100644 (file)
@@ -24,7 +24,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -72,6 +72,8 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_SOCKET_H */
 
 
index 871f89b7fbdaf08a0629679f01d804337804cbc7..595391f0f98c65e2bddbcbbe70b7e4d5062082d9 100644 (file)
@@ -22,7 +22,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -70,5 +70,7 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_SOCKET_H */
 
index 90a2e573c7e679ac92300734e3641f7d5d5b45e0..43e32621da7d01ab20ad81f0c520d6ee83682434 100644 (file)
@@ -22,7 +22,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -70,4 +70,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_SOCKET_H */
index 23d6759bb57b8dd6af9a824e78ce7335dede1d80..c567adc8bea535fb5bcc15156a51f4af55424bf3 100644 (file)
@@ -31,7 +31,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -79,4 +79,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_IA64_SOCKET_H */
index 5e7088a26726cc0133ae3a6f166f3597832646a6..519afa2755db5c8738bc7138f67aecc408d27fd2 100644 (file)
@@ -22,7 +22,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -70,4 +70,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_M32R_SOCKET_H */
index 57981e4fe2bc94c143070ee99ecf66d09ceae223..b8ef965705cf6ca4b7ceb890528d63e5236fb34e 100644 (file)
@@ -62,7 +62,7 @@ static int __init uart8250_init_bcma(void)
 
                p->mapbase = (unsigned int) bcma_port->regs;
                p->membase = (void *) bcma_port->regs;
-               p->irq = bcma_port->irq + 2;
+               p->irq = bcma_port->irq;
                p->uartclk = bcma_port->baud_base;
                p->regshift = bcma_port->reg_shift;
                p->iotype = UPIO_MEM;
index 17307ab90474271e4c77f9d48bfb775f2049db74..3e68bfbda6bc2f8e574a614a23d6713053182233 100644 (file)
@@ -28,9 +28,7 @@
 #define SO_LINGER      0x0080  /* Block on close of a reliable
                                   socket to transmit pending data.  */
 #define SO_OOBINLINE 0x0100    /* Receive out-of-band data in-band.  */
-#if 0
-To add: #define SO_REUSEPORT 0x0200    /* Allow local address and port reuse.  */
-#endif
+#define SO_REUSEPORT 0x0200    /* Allow local address and port reuse.  */
 
 #define SO_TYPE                0x1008  /* Compatible name for SO_STYLE.  */
 #define SO_STYLE       SO_TYPE /* Synonym */
@@ -90,5 +88,6 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
 
 #endif /* _UAPI_ASM_SOCKET_H */
index af5366bbfe62727b09e2d47474e78a7483bb3a13..5c7c7c988544558f632a84ab5f529801a27b8963 100644 (file)
@@ -22,7 +22,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -70,4 +70,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_SOCKET_H */
index d9ff4731253bb6e8f6402686e2401e251126ecb2..526e4b9aece0a0480f1631bcb492c83ffac2c735 100644 (file)
@@ -13,7 +13,7 @@
 #define SO_BROADCAST   0x0020
 #define SO_LINGER      0x0080
 #define SO_OOBINLINE   0x0100
-/* To add :#define SO_REUSEPORT 0x0200 */
+#define SO_REUSEPORT   0x0200
 #define SO_SNDBUF      0x1001
 #define SO_RCVBUF      0x1002
 #define SO_SNDBUFFORCE 0x100a
@@ -69,6 +69,7 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               0x4024
 
+#define SO_LOCK_FILTER         0x4025
 
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
index eb0b1864d400b2a01386ed3a77fedb300a560227..a26dcaece509490746ab8b2a5d254125f6d4571f 100644 (file)
@@ -29,7 +29,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_RCVLOWAT    16
 #define SO_SNDLOWAT    17
 #define SO_RCVTIMEO    18
@@ -77,4 +77,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_POWERPC_SOCKET_H */
index 436d07c23be8febc9ad245fb73e4f1671a004cd9..f99eea7fff0fc4af85cf41ab1fd91ff6e402352b 100644 (file)
@@ -28,7 +28,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -76,4 +76,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _ASM_SOCKET_H */
index c83a937ead00676eefef950b6c00d77cd644c8a9..cbbad74b2e06a0c6405ecabd4d054887b404668f 100644 (file)
@@ -15,7 +15,7 @@
 #define SO_PEERCRED    0x0040
 #define SO_LINGER      0x0080
 #define SO_OOBINLINE   0x0100
-/* To add :#define SO_REUSEPORT 0x0200 */
+#define SO_REUSEPORT   0x0200
 #define SO_BSDCOMPAT    0x0400
 #define SO_RCVLOWAT     0x0800
 #define SO_SNDLOWAT     0x1000
@@ -66,6 +66,7 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               0x0027
 
+#define SO_LOCK_FILTER         0x0028
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
index b1314ebf1f7243713e29cd179ff2499f6b12ac3c..d8926c30362946475822ff21ca6a4d5dc9f20cbf 100644 (file)
@@ -274,8 +274,8 @@ static void uml_net_poll_controller(struct net_device *dev)
 static void uml_net_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRIVER_NAME);
-       strcpy(info->version, "42");
+       strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+       strlcpy(info->version, "42", sizeof(info->version));
 }
 
 static const struct ethtool_ops uml_net_ethtool_ops = {
@@ -293,8 +293,9 @@ static void uml_net_user_timer_expire(unsigned long _conn)
 #endif
 }
 
-static int setup_etheraddr(char *str, unsigned char *addr, char *name)
+static void setup_etheraddr(struct net_device *dev, char *str)
 {
+       unsigned char *addr = dev->dev_addr;
        char *end;
        int i;
 
@@ -334,13 +335,12 @@ static int setup_etheraddr(char *str, unsigned char *addr, char *name)
                       addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4],
                       addr[5]);
        }
-       return 0;
+       return;
 
 random:
        printk(KERN_INFO
-              "Choosing a random ethernet address for device %s\n", name);
-       eth_random_addr(addr);
-       return 1;
+              "Choosing a random ethernet address for device %s\n", dev->name);
+       eth_hw_addr_random(dev);
 }
 
 static DEFINE_SPINLOCK(devices_lock);
@@ -392,7 +392,6 @@ static void eth_configure(int n, void *init, char *mac,
        struct net_device *dev;
        struct uml_net_private *lp;
        int err, size;
-       int random_mac;
 
        size = transport->private_size + sizeof(struct uml_net_private);
 
@@ -419,9 +418,9 @@ static void eth_configure(int n, void *init, char *mac,
         */
        snprintf(dev->name, sizeof(dev->name), "eth%d", n);
 
-       random_mac = setup_etheraddr(mac, device->mac, dev->name);
+       setup_etheraddr(dev, mac);
 
-       printk(KERN_INFO "Netdevice %d (%pM) : ", n, device->mac);
+       printk(KERN_INFO "Netdevice %d (%pM) : ", n, dev->dev_addr);
 
        lp = netdev_priv(dev);
        /* This points to the transport private data. It's still clear, but we
@@ -468,17 +467,12 @@ static void eth_configure(int n, void *init, char *mac,
        init_timer(&lp->tl);
        spin_lock_init(&lp->lock);
        lp->tl.function = uml_net_user_timer_expire;
-       memcpy(lp->mac, device->mac, sizeof(lp->mac));
+       memcpy(lp->mac, dev->dev_addr, sizeof(lp->mac));
 
        if ((transport->user->init != NULL) &&
            ((*transport->user->init)(&lp->user, dev) != 0))
                goto out_unregister;
 
-       /* don't use eth_mac_addr, it will not work here */
-       memcpy(dev->dev_addr, device->mac, ETH_ALEN);
-       if (random_mac)
-               dev->addr_assign_type |= NET_ADDR_RANDOM;
-
        dev->mtu = transport->user->mtu;
        dev->netdev_ops = &uml_netdev_ops;
        dev->ethtool_ops = &uml_net_ethtool_ops;
index 5c367f22595bd5bf915b4c55e33892d4833f17e5..012ac87d49004ee5d2d584a74a1274b2d20e2d07 100644 (file)
@@ -18,7 +18,6 @@ struct uml_net {
        struct net_device *dev;
        struct platform_device pdev;
        int index;
-       unsigned char mac[ETH_ALEN];
 };
 
 struct uml_net_private {
index 1b9c22bea8a7de8f6e63b200d77733bd2bb0f3c5..a0795da22c0273286119312018f5dfe21c4ac9ca 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
 
-#if defined(CONFIG_CRYPTO_CTR) || defined(CONFIG_CRYPTO_CTR_MODULE)
-#define HAS_CTR
-#endif
-
 #if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE)
 #define HAS_PCBC
 #endif
@@ -395,12 +391,6 @@ static int ablk_ctr_init(struct crypto_tfm *tfm)
        return ablk_init_common(tfm, "__driver-ctr-aes-aesni");
 }
 
-#ifdef HAS_CTR
-static int ablk_rfc3686_ctr_init(struct crypto_tfm *tfm)
-{
-       return ablk_init_common(tfm, "rfc3686(__driver-ctr-aes-aesni)");
-}
-#endif
 #endif
 
 #ifdef HAS_PCBC
@@ -1158,33 +1148,6 @@ static struct crypto_alg aesni_algs[] = { {
                        .maxauthsize    = 16,
                },
        },
-#ifdef HAS_CTR
-}, {
-       .cra_name               = "rfc3686(ctr(aes))",
-       .cra_driver_name        = "rfc3686-ctr-aes-aesni",
-       .cra_priority           = 400,
-       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-       .cra_blocksize          = 1,
-       .cra_ctxsize            = sizeof(struct async_helper_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_ablkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_init               = ablk_rfc3686_ctr_init,
-       .cra_exit               = ablk_exit,
-       .cra_u = {
-               .ablkcipher = {
-                       .min_keysize = AES_MIN_KEY_SIZE +
-                                      CTR_RFC3686_NONCE_SIZE,
-                       .max_keysize = AES_MAX_KEY_SIZE +
-                                      CTR_RFC3686_NONCE_SIZE,
-                       .ivsize      = CTR_RFC3686_IV_SIZE,
-                       .setkey      = ablk_set_key,
-                       .encrypt     = ablk_encrypt,
-                       .decrypt     = ablk_decrypt,
-                       .geniv       = "seqiv",
-               },
-       },
-#endif
 #endif
 #ifdef HAS_PCBC
 }, {
index 38079be1cf1ebc98fa6d9a61aebd59ff81822f78..35905cb6e419a661c04e24bf205f5c4e1f1982f5 100644 (file)
@@ -32,7 +32,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT   15
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
 #define SO_RCVLOWAT    18
@@ -81,4 +81,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* _XTENSA_SOCKET_H */
index 4ca7222cfeb6ac4bfcf32e4a97a072e1535577a7..1f2997cbfdd480937f6ca0c86abd3e9d7e73d5b0 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <crypto/algapi.h>
 #include <crypto/ctr.h>
+#include <crypto/internal/skcipher.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -25,10 +26,15 @@ struct crypto_ctr_ctx {
 };
 
 struct crypto_rfc3686_ctx {
-       struct crypto_blkcipher *child;
+       struct crypto_ablkcipher *child;
        u8 nonce[CTR_RFC3686_NONCE_SIZE];
 };
 
+struct crypto_rfc3686_req_ctx {
+       u8 iv[CTR_RFC3686_BLOCK_SIZE];
+       struct ablkcipher_request subreq CRYPTO_MINALIGN_ATTR;
+};
+
 static int crypto_ctr_setkey(struct crypto_tfm *parent, const u8 *key,
                             unsigned int keylen)
 {
@@ -243,11 +249,11 @@ static struct crypto_template crypto_ctr_tmpl = {
        .module = THIS_MODULE,
 };
 
-static int crypto_rfc3686_setkey(struct crypto_tfm *parent, const u8 *key,
-                                unsigned int keylen)
+static int crypto_rfc3686_setkey(struct crypto_ablkcipher *parent,
+                                const u8 *key, unsigned int keylen)
 {
-       struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(parent);
-       struct crypto_blkcipher *child = ctx->child;
+       struct crypto_rfc3686_ctx *ctx = crypto_ablkcipher_ctx(parent);
+       struct crypto_ablkcipher *child = ctx->child;
        int err;
 
        /* the nonce is stored in bytes at end of key */
@@ -259,59 +265,64 @@ static int crypto_rfc3686_setkey(struct crypto_tfm *parent, const u8 *key,
 
        keylen -= CTR_RFC3686_NONCE_SIZE;
 
-       crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
-       crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
-                                         CRYPTO_TFM_REQ_MASK);
-       err = crypto_blkcipher_setkey(child, key, keylen);
-       crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
-                                    CRYPTO_TFM_RES_MASK);
+       crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(parent) &
+                                   CRYPTO_TFM_REQ_MASK);
+       err = crypto_ablkcipher_setkey(child, key, keylen);
+       crypto_ablkcipher_set_flags(parent, crypto_ablkcipher_get_flags(child) &
+                                   CRYPTO_TFM_RES_MASK);
 
        return err;
 }
 
-static int crypto_rfc3686_crypt(struct blkcipher_desc *desc,
-                               struct scatterlist *dst,
-                               struct scatterlist *src, unsigned int nbytes)
+static int crypto_rfc3686_crypt(struct ablkcipher_request *req)
 {
-       struct crypto_blkcipher *tfm = desc->tfm;
-       struct crypto_rfc3686_ctx *ctx = crypto_blkcipher_ctx(tfm);
-       struct crypto_blkcipher *child = ctx->child;
-       unsigned long alignmask = crypto_blkcipher_alignmask(tfm);
-       u8 ivblk[CTR_RFC3686_BLOCK_SIZE + alignmask];
-       u8 *iv = PTR_ALIGN(ivblk + 0, alignmask + 1);
-       u8 *info = desc->info;
-       int err;
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct crypto_rfc3686_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       struct crypto_ablkcipher *child = ctx->child;
+       unsigned long align = crypto_ablkcipher_alignmask(tfm);
+       struct crypto_rfc3686_req_ctx *rctx =
+               (void *)PTR_ALIGN((u8 *)ablkcipher_request_ctx(req), align + 1);
+       struct ablkcipher_request *subreq = &rctx->subreq;
+       u8 *iv = rctx->iv;
 
        /* set up counter block */
        memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
-       memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE);
+       memcpy(iv + CTR_RFC3686_NONCE_SIZE, req->info, CTR_RFC3686_IV_SIZE);
 
        /* initialize counter portion of counter block */
        *(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
                cpu_to_be32(1);
 
-       desc->tfm = child;
-       desc->info = iv;
-       err = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
-       desc->tfm = tfm;
-       desc->info = info;
+       ablkcipher_request_set_tfm(subreq, child);
+       ablkcipher_request_set_callback(subreq, req->base.flags,
+                                       req->base.complete, req->base.data);
+       ablkcipher_request_set_crypt(subreq, req->src, req->dst, req->nbytes,
+                                    iv);
 
-       return err;
+       return crypto_ablkcipher_encrypt(subreq);
 }
 
 static int crypto_rfc3686_init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_instance *inst = (void *)tfm->__crt_alg;
-       struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+       struct crypto_skcipher_spawn *spawn = crypto_instance_ctx(inst);
        struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct crypto_blkcipher *cipher;
+       struct crypto_ablkcipher *cipher;
+       unsigned long align;
 
-       cipher = crypto_spawn_blkcipher(spawn);
+       cipher = crypto_spawn_skcipher(spawn);
        if (IS_ERR(cipher))
                return PTR_ERR(cipher);
 
        ctx->child = cipher;
 
+       align = crypto_tfm_alg_alignmask(tfm);
+       align &= ~(crypto_tfm_ctx_alignment() - 1);
+       tfm->crt_ablkcipher.reqsize = align +
+               sizeof(struct crypto_rfc3686_req_ctx) +
+               crypto_ablkcipher_reqsize(cipher);
+
        return 0;
 }
 
@@ -319,74 +330,110 @@ static void crypto_rfc3686_exit_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
 
-       crypto_free_blkcipher(ctx->child);
+       crypto_free_ablkcipher(ctx->child);
 }
 
 static struct crypto_instance *crypto_rfc3686_alloc(struct rtattr **tb)
 {
+       struct crypto_attr_type *algt;
        struct crypto_instance *inst;
        struct crypto_alg *alg;
+       struct crypto_skcipher_spawn *spawn;
+       const char *cipher_name;
        int err;
 
-       err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
-       if (err)
+       algt = crypto_get_attr_type(tb);
+       err = PTR_ERR(algt);
+       if (IS_ERR(algt))
                return ERR_PTR(err);
 
-       alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
-                                 CRYPTO_ALG_TYPE_MASK);
-       err = PTR_ERR(alg);
-       if (IS_ERR(alg))
+       if ((algt->type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & algt->mask)
+               return ERR_PTR(-EINVAL);
+
+       cipher_name = crypto_attr_alg_name(tb[1]);
+       err = PTR_ERR(cipher_name);
+       if (IS_ERR(cipher_name))
                return ERR_PTR(err);
 
+       inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+       if (!inst)
+               return ERR_PTR(-ENOMEM);
+
+       spawn = crypto_instance_ctx(inst);
+
+       crypto_set_skcipher_spawn(spawn, inst);
+       err = crypto_grab_skcipher(spawn, cipher_name, 0,
+                                  crypto_requires_sync(algt->type,
+                                                       algt->mask));
+       if (err)
+               goto err_free_inst;
+
+       alg = crypto_skcipher_spawn_alg(spawn);
+
        /* We only support 16-byte blocks. */
        err = -EINVAL;
-       if (alg->cra_blkcipher.ivsize != CTR_RFC3686_BLOCK_SIZE)
-               goto out_put_alg;
+       if (alg->cra_ablkcipher.ivsize != CTR_RFC3686_BLOCK_SIZE)
+               goto err_drop_spawn;
 
        /* Not a stream cipher? */
        if (alg->cra_blocksize != 1)
-               goto out_put_alg;
+               goto err_drop_spawn;
 
-       inst = crypto_alloc_instance("rfc3686", alg);
-       if (IS_ERR(inst))
-               goto out;
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "rfc3686(%s)",
+                    alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
+               goto err_drop_spawn;
+       if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                    "rfc3686(%s)", alg->cra_driver_name) >=
+                       CRYPTO_MAX_ALG_NAME)
+               goto err_drop_spawn;
 
-       inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
        inst->alg.cra_priority = alg->cra_priority;
        inst->alg.cra_blocksize = 1;
        inst->alg.cra_alignmask = alg->cra_alignmask;
-       inst->alg.cra_type = &crypto_blkcipher_type;
 
-       inst->alg.cra_blkcipher.ivsize = CTR_RFC3686_IV_SIZE;
-       inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize
-                                             + CTR_RFC3686_NONCE_SIZE;
-       inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize
-                                             + CTR_RFC3686_NONCE_SIZE;
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                             (alg->cra_flags & CRYPTO_ALG_ASYNC);
+       inst->alg.cra_type = &crypto_ablkcipher_type;
+
+       inst->alg.cra_ablkcipher.ivsize = CTR_RFC3686_IV_SIZE;
+       inst->alg.cra_ablkcipher.min_keysize =
+               alg->cra_ablkcipher.min_keysize + CTR_RFC3686_NONCE_SIZE;
+       inst->alg.cra_ablkcipher.max_keysize =
+               alg->cra_ablkcipher.max_keysize + CTR_RFC3686_NONCE_SIZE;
 
-       inst->alg.cra_blkcipher.geniv = "seqiv";
+       inst->alg.cra_ablkcipher.geniv = "seqiv";
+
+       inst->alg.cra_ablkcipher.setkey = crypto_rfc3686_setkey;
+       inst->alg.cra_ablkcipher.encrypt = crypto_rfc3686_crypt;
+       inst->alg.cra_ablkcipher.decrypt = crypto_rfc3686_crypt;
 
        inst->alg.cra_ctxsize = sizeof(struct crypto_rfc3686_ctx);
 
        inst->alg.cra_init = crypto_rfc3686_init_tfm;
        inst->alg.cra_exit = crypto_rfc3686_exit_tfm;
 
-       inst->alg.cra_blkcipher.setkey = crypto_rfc3686_setkey;
-       inst->alg.cra_blkcipher.encrypt = crypto_rfc3686_crypt;
-       inst->alg.cra_blkcipher.decrypt = crypto_rfc3686_crypt;
-
-out:
-       crypto_mod_put(alg);
        return inst;
 
-out_put_alg:
-       inst = ERR_PTR(err);
-       goto out;
+err_drop_spawn:
+       crypto_drop_skcipher(spawn);
+err_free_inst:
+       kfree(inst);
+       return ERR_PTR(err);
+}
+
+static void crypto_rfc3686_free(struct crypto_instance *inst)
+{
+       struct crypto_skcipher_spawn *spawn = crypto_instance_ctx(inst);
+
+       crypto_drop_skcipher(spawn);
+       kfree(inst);
 }
 
 static struct crypto_template crypto_rfc3686_tmpl = {
        .name = "rfc3686",
        .alloc = crypto_rfc3686_alloc,
-       .free = crypto_ctr_free,
+       .free = crypto_rfc3686_free,
        .module = THIS_MODULE,
 };
 
index 7ae2130e1b002890900907fc415b1eb51094e8a7..87ef7d66bc20e05d6247cb42de5372fcaea3c9f6 100644 (file)
@@ -1591,6 +1591,10 @@ static int do_test(int m)
                                   speed_template_16_24_32);
                test_acipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0,
                                   speed_template_16_24_32);
+               test_acipher_speed("rfc3686(ctr(aes))", ENCRYPT, sec, NULL, 0,
+                                  speed_template_20_28_36);
+               test_acipher_speed("rfc3686(ctr(aes))", DECRYPT, sec, NULL, 0,
+                                  speed_template_20_28_36);
                break;
 
        case 501:
index cd2068524f3f6766696cf5f350d546bb2c9c644b..ecdeeb1a7b05116301c2b6bf315319e463d09264 100644 (file)
@@ -51,6 +51,7 @@ static u8 speed_template_8_16[] = {8, 16, 0};
 static u8 speed_template_8_32[] = {8, 32, 0};
 static u8 speed_template_16_32[] = {16, 32, 0};
 static u8 speed_template_16_24_32[] = {16, 24, 32, 0};
+static u8 speed_template_20_28_36[] = {20, 28, 36, 0};
 static u8 speed_template_32_40_48[] = {32, 40, 48, 0};
 static u8 speed_template_32_48[] = {32, 48, 0};
 static u8 speed_template_32_48_64[] = {32, 48, 64, 0};
index 19e3fbfd5757368790980dfec756135e981b0eaf..04f7c86ea3d83e9a29ad2a595c3dbbbcd008fa2e 100644 (file)
@@ -31,6 +31,8 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
 int bcma_bus_suspend(struct bcma_bus *bus);
 int bcma_bus_resume(struct bcma_bus *bus);
 #endif
+struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+                                       u8 unit);
 
 /* scan.c */
 int bcma_bus_scan(struct bcma_bus *bus);
index e461ad25fda4825dbc36a632d5781015843eb268..28fa50ad87bee80630758b2c5ace883d02ce2c0d 100644 (file)
@@ -329,7 +329,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
                return;
        }
 
-       irq = bcma_core_mips_irq(cc->core);
+       irq = bcma_core_irq(cc->core);
 
        /* Determine the registers of the UARTs */
        cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
index c62c788b3289f0d338667dfd3ecaa4f50d39ada6..932b101dee36a5398a53904072d32d32541af23a 100644 (file)
@@ -264,7 +264,7 @@ static u32 bcma_pmu_pll_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
 }
 
 /* query bus clock frequency for PMU-enabled chipcommon */
-static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
+u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
 {
        struct bcma_bus *bus = cc->core->bus;
 
@@ -293,6 +293,7 @@ static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
        }
        return BCMA_CC_PMU_HT_CLOCK;
 }
+EXPORT_SYMBOL_GPL(bcma_pmu_get_bus_clock);
 
 /* query cpu clock frequency for PMU-enabled chipcommon */
 u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
index 792daad28cbc6fa883a2e20911b33dbe840a49ba..9fe86ee16c6691f565fb33f1f563094f07266666 100644 (file)
@@ -74,28 +74,41 @@ static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
                return dev->core_index;
        flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
 
-       return flag & 0x1F;
+       if (flag)
+               return flag & 0x1F;
+       else
+               return 0x3f;
 }
 
 /* Get the MIPS IRQ assignment for a specified device.
  * If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ * If not supported, 6 is returned.
  */
-unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
 {
        struct bcma_device *mdev = dev->bus->drv_mips.core;
        u32 irqflag;
        unsigned int irq;
 
        irqflag = bcma_core_mips_irqflag(dev);
+       if (irqflag == 0x3f)
+               return 6;
 
-       for (irq = 1; irq <= 4; irq++)
+       for (irq = 0; irq <= 4; irq++)
                if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
                    (1 << irqflag))
                        return irq;
 
-       return 0;
+       return 5;
+}
+
+unsigned int bcma_core_irq(struct bcma_device *dev)
+{
+       unsigned int mips_irq = bcma_core_mips_irq(dev);
+       return mips_irq <= 4 ? mips_irq + 2 : 0;
 }
-EXPORT_SYMBOL(bcma_core_mips_irq);
+EXPORT_SYMBOL(bcma_core_irq);
 
 static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
 {
@@ -114,7 +127,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
                            ~(1 << irqflag));
-       else
+       else if (oldirq != 5)
                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
 
        /* assign the new one */
@@ -123,9 +136,9 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
                            (1 << irqflag));
        } else {
-               u32 oldirqflag = bcma_read32(mdev,
-                                            BCMA_MIPS_MIPS74K_INTMASK(irq));
-               if (oldirqflag) {
+               u32 irqinitmask = bcma_read32(mdev,
+                                             BCMA_MIPS_MIPS74K_INTMASK(irq));
+               if (irqinitmask) {
                        struct bcma_device *core;
 
                        /* backplane irq line is in use, find out who uses
@@ -133,7 +146,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
                         */
                        list_for_each_entry(core, &bus->cores, list) {
                                if ((1 << bcma_core_mips_irqflag(core)) ==
-                                   oldirqflag) {
+                                   irqinitmask) {
                                        bcma_core_mips_set_irq(core, 0);
                                        break;
                                }
@@ -143,15 +156,31 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
                             1 << irqflag);
        }
 
-       bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
-                 dev->id.id, oldirq + 2, irq + 2);
+       bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
+                  dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
+}
+
+static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
+                                       u16 coreid, u8 unit)
+{
+       struct bcma_device *core;
+
+       core = bcma_find_core_unit(bus, coreid, unit);
+       if (!core) {
+               bcma_warn(bus,
+                         "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
+                         coreid, unit);
+               return;
+       }
+
+       bcma_core_mips_set_irq(core, irq);
 }
 
 static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
 {
        int i;
        static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
-       printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+       printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
        for (i = 0; i <= 6; i++)
                printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
        printk("\n");
@@ -227,6 +256,32 @@ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
        mcore->early_setup_done = true;
 }
 
+static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
+{
+       struct bcma_device *cpu, *pcie, *i2s;
+
+       /* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
+        * (IRQ flags > 7 are ignored when setting the interrupt masks)
+        */
+       if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
+           bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
+               return;
+
+       cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+       pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
+       i2s = bcma_find_core(bus, BCMA_CORE_I2S);
+       if (cpu && pcie && i2s &&
+           bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
+           bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
+           bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
+               bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
+               bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
+               bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
+               bcma_debug(bus,
+                          "Moved i2s interrupt to oob line 7 instead of 8\n");
+       }
+}
+
 void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 {
        struct bcma_bus *bus;
@@ -236,43 +291,55 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
        if (mcore->setup_done)
                return;
 
-       bcma_info(bus, "Initializing MIPS core...\n");
+       bcma_debug(bus, "Initializing MIPS core...\n");
 
        bcma_core_mips_early_init(mcore);
 
-       mcore->assigned_irqs = 1;
-
-       /* Assign IRQs to all cores on the bus */
-       list_for_each_entry(core, &bus->cores, list) {
-               int mips_irq;
-               if (core->irq)
-                       continue;
-
-               mips_irq = bcma_core_mips_irq(core);
-               if (mips_irq > 4)
-                       core->irq = 0;
-               else
-                       core->irq = mips_irq + 2;
-               if (core->irq > 5)
-                       continue;
-               switch (core->id.id) {
-               case BCMA_CORE_PCI:
-               case BCMA_CORE_PCIE:
-               case BCMA_CORE_ETHERNET:
-               case BCMA_CORE_ETHERNET_GBIT:
-               case BCMA_CORE_MAC_GBIT:
-               case BCMA_CORE_80211:
-               case BCMA_CORE_USB20_HOST:
-                       /* These devices get their own IRQ line if available,
-                        * the rest goes on IRQ0
-                        */
-                       if (mcore->assigned_irqs <= 4)
-                               bcma_core_mips_set_irq(core,
-                                                      mcore->assigned_irqs++);
-                       break;
+       bcma_fix_i2s_irqflag(bus);
+
+       switch (bus->chipinfo.id) {
+       case BCMA_CHIP_ID_BCM4716:
+       case BCMA_CHIP_ID_BCM4748:
+               bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+               bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+               bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
+               bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
+               bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+               bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
+               break;
+       case BCMA_CHIP_ID_BCM5356:
+       case BCMA_CHIP_ID_BCM47162:
+       case BCMA_CHIP_ID_BCM53572:
+               bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+               bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+               bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+               break;
+       case BCMA_CHIP_ID_BCM5357:
+       case BCMA_CHIP_ID_BCM4749:
+               bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+               bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+               bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
+               bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+               bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
+               break;
+       case BCMA_CHIP_ID_BCM4706:
+               bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
+               bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
+                                           0);
+               bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
+               bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
+               bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
+                                           0);
+               break;
+       default:
+               list_for_each_entry(core, &bus->cores, list) {
+                       core->irq = bcma_core_irq(core);
                }
+               bcma_err(bus,
+                        "Unknown device (0x%x) found, can not configure IRQs\n",
+                        bus->chipinfo.id);
        }
-       bcma_info(bus, "IRQ reconfiguration done\n");
+       bcma_debug(bus, "IRQ reconfiguration done\n");
        bcma_core_mips_dump_irq(bus);
 
        mcore->setup_done = true;
index af0c9fabee54f212833809ecbfab0007bc9105fb..d3bde6cec927643bdf02445e387e97d4d5f29d69 100644 (file)
@@ -94,19 +94,19 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
        if (dev == 0) {
                /* we support only two functions on device 0 */
                if (func > 1)
-                       return -EINVAL;
+                       goto out;
 
                /* accesses to config registers with offsets >= 256
                 * requires indirect access.
                 */
                if (off >= PCI_CONFIG_SPACE_SIZE) {
                        addr = (func << 12);
-                       addr |= (off & 0x0FFF);
+                       addr |= (off & 0x0FFC);
                        val = bcma_pcie_read_config(pc, addr);
                } else {
                        addr = BCMA_CORE_PCI_PCICFG0;
                        addr |= (func << 8);
-                       addr |= (off & 0xfc);
+                       addr |= (off & 0xFC);
                        val = pcicore_read32(pc, addr);
                }
        } else {
@@ -119,11 +119,9 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
                        goto out;
 
                if (mips_busprobe32(val, mmio)) {
-                       val = 0xffffffff;
+                       val = 0xFFFFFFFF;
                        goto unmap;
                }
-
-               val = readl(mmio);
        }
        val >>= (8 * (off & 3));
 
@@ -151,7 +149,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
                                   const void *buf, int len)
 {
        int err = -EINVAL;
-       u32 addr = 0, val = 0;
+       u32 addr, val;
        void __iomem *mmio = 0;
        u16 chipid = pc->core->bus->chipinfo.id;
 
@@ -159,16 +157,22 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
        if (unlikely(len != 1 && len != 2 && len != 4))
                goto out;
        if (dev == 0) {
+               /* we support only two functions on device 0 */
+               if (func > 1)
+                       goto out;
+
                /* accesses to config registers with offsets >= 256
                 * requires indirect access.
                 */
-               if (off < PCI_CONFIG_SPACE_SIZE) {
-                       addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
+               if (off >= PCI_CONFIG_SPACE_SIZE) {
+                       addr = (func << 12);
+                       addr |= (off & 0x0FFC);
+                       val = bcma_pcie_read_config(pc, addr);
+               } else {
+                       addr = BCMA_CORE_PCI_PCICFG0;
                        addr |= (func << 8);
-                       addr |= (off & 0xfc);
-                       mmio = ioremap_nocache(addr, sizeof(val));
-                       if (!mmio)
-                               goto out;
+                       addr |= (off & 0xFC);
+                       val = pcicore_read32(pc, addr);
                }
        } else {
                addr = bcma_get_cfgspace_addr(pc, dev, func, off);
@@ -180,19 +184,17 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
                        goto out;
 
                if (mips_busprobe32(val, mmio)) {
-                       val = 0xffffffff;
+                       val = 0xFFFFFFFF;
                        goto unmap;
                }
        }
 
        switch (len) {
        case 1:
-               val = readl(mmio);
                val &= ~(0xFF << (8 * (off & 3)));
                val |= *((const u8 *)buf) << (8 * (off & 3));
                break;
        case 2:
-               val = readl(mmio);
                val &= ~(0xFFFF << (8 * (off & 3)));
                val |= *((const u16 *)buf) << (8 * (off & 3));
                break;
@@ -200,13 +202,14 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
                val = *((const u32 *)buf);
                break;
        }
-       if (dev == 0 && !addr) {
+       if (dev == 0) {
                /* accesses to config registers with offsets >= 256
                 * requires indirect access.
                 */
-               addr = (func << 12);
-               addr |= (off & 0x0FFF);
-               bcma_pcie_write_config(pc, addr, val);
+               if (off >= PCI_CONFIG_SPACE_SIZE)
+                       bcma_pcie_write_config(pc, addr, val);
+               else
+                       pcicore_write32(pc, addr, val);
        } else {
                writel(val, mmio);
 
@@ -276,7 +279,7 @@ static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev,
        /* check for Header type 0 */
        bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
                                sizeof(u8));
-       if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
+       if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL)
                return cap_ptr;
 
        /* check if the capability pointer field exists */
@@ -426,7 +429,7 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
        /* Reset RC */
        usleep_range(3000, 5000);
        pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
-       usleep_range(1000, 2000);
+       msleep(50);
        pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
                        BCMA_CORE_PCI_CTL_RST_OE);
 
@@ -488,6 +491,17 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
 
        bcma_core_pci_enable_crs(pc);
 
+       if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706 ||
+           bus->chipinfo.id == BCMA_CHIP_ID_BCM4716) {
+               u16 val16;
+               bcma_extpci_read_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
+                                       &val16, sizeof(val16));
+               val16 |= (2 << 5);      /* Max payload size of 512 */
+               val16 |= (2 << 12);     /* MRRS 512 */
+               bcma_extpci_write_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
+                                        &val16, sizeof(val16));
+       }
+
        /* Enable PCI bridge BAR0 memory & master access */
        tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
        bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
@@ -576,7 +590,7 @@ int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
        pr_info("PCI: Fixing up device %s\n", pci_name(dev));
 
        /* Fix up interrupt lines */
-       dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
+       dev->irq = bcma_core_irq(pc_host->pdev->core);
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 
        return 0;
@@ -595,6 +609,6 @@ int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
 
        pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
                               pci_ops);
-       return bcma_core_mips_irq(pc_host->pdev->core) + 2;
+       return bcma_core_irq(pc_host->pdev->core);
 }
 EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
index 4a92f647b58bdef4fa28f28b772d960036469c78..ff8528925322e2808d257caf32b5cd2c89917b4d 100644 (file)
@@ -81,8 +81,8 @@ struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
 }
 EXPORT_SYMBOL_GPL(bcma_find_core);
 
-static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
-                                              u8 unit)
+struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+                                       u8 unit)
 {
        struct bcma_device *core;
 
index e7a711f53a6f7cd8f0b1316d324034b1ca2acc1c..2b27bff2591a029a193878812e3e8d00ca1134b4 100644 (file)
@@ -270,7 +270,7 @@ static int fwnet_header_cache(const struct neighbour *neigh,
        if (type == cpu_to_be16(ETH_P_802_3))
                return -1;
        net = neigh->dev;
-       h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h));
+       h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h)));
        h->h_proto = type;
        memcpy(h->h_dest, neigh->ha, net->addr_len);
        hh->hh_len = FWNET_HLEN;
@@ -282,7 +282,7 @@ static int fwnet_header_cache(const struct neighbour *neigh,
 static void fwnet_header_cache_update(struct hh_cache *hh,
                const struct net_device *net, const unsigned char *haddr)
 {
-       memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len);
+       memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
 }
 
 static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
@@ -398,11 +398,11 @@ static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net,
 
        new->datagram_label = datagram_label;
        new->datagram_size = dg_size;
-       new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15);
+       new->skb = dev_alloc_skb(dg_size + LL_RESERVED_SPACE(net));
        if (new->skb == NULL)
                goto fail_w_fi;
 
-       skb_reserve(new->skb, (net->hard_header_len + 15) & ~15);
+       skb_reserve(new->skb, LL_RESERVED_SPACE(net));
        new->pbuf = skb_put(new->skb, dg_size);
        memcpy(new->pbuf + frag_off, frag_buf, frag_len);
        list_add_tail(&new->pd_link, &peer->pd_list);
@@ -520,7 +520,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
        dev = netdev_priv(net);
        /* Write metadata, and then pass to the receive level */
        skb->dev = net;
-       skb->ip_summed = CHECKSUM_UNNECESSARY;  /* don't check it */
+       skb->ip_summed = CHECKSUM_NONE;
 
        /*
         * Parse the encapsulation header. This actually does the job of
@@ -690,14 +690,14 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
                buf++;
                len -= RFC2374_UNFRAG_HDR_SIZE;
 
-               skb = dev_alloc_skb(len + net->hard_header_len + 15);
+               skb = dev_alloc_skb(len + LL_RESERVED_SPACE(net));
                if (unlikely(!skb)) {
                        dev_err(&net->dev, "out of memory\n");
                        net->stats.rx_dropped++;
 
                        return -ENOMEM;
                }
-               skb_reserve(skb, (net->hard_header_len + 15) & ~15);
+               skb_reserve(skb, LL_RESERVED_SPACE(net));
                memcpy(skb_put(skb, len), buf, len);
 
                return fwnet_finish_incoming_packet(net, skb, source_node_id,
index 5b152a366dffd550e6b149a8bc56f841db9c1c6b..429141078eec632d2409b75f267193f4fb242f96 100644 (file)
@@ -135,6 +135,7 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
        struct net_device *event_netdev = ifa->ifa_dev->dev;
        struct nes_device *nesdev;
        struct net_device *netdev;
+       struct net_device *upper_dev;
        struct nes_vnic *nesvnic;
        unsigned int is_bonded;
 
@@ -145,8 +146,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
                                nesdev, nesdev->netdev[0]->name);
                netdev = nesdev->netdev[0];
                nesvnic = netdev_priv(netdev);
+               upper_dev = netdev_master_upper_dev_get(netdev);
                is_bonded = netif_is_bond_slave(netdev) &&
-                           (netdev->master == event_netdev);
+                           (upper_dev == event_netdev);
                if ((netdev == event_netdev) || is_bonded) {
                        if (nesvnic->rdma_enabled == 0) {
                                nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
@@ -179,9 +181,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
                                        /* fall through */
                                case NETDEV_CHANGEADDR:
                                        /* Add the address to the IP table */
-                                       if (netdev->master)
+                                       if (upper_dev)
                                                nesvnic->local_ipaddr =
-                                                       ((struct in_device *)netdev->master->ip_ptr)->ifa_list->ifa_address;
+                                                       ((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address;
                                        else
                                                nesvnic->local_ipaddr = ifa->ifa_address;
 
index 22ea67eea5dceb7dfc9ccc136efef805273fe4c2..24b9f1a0107b9174b7035d12b560f69fa90633c1 100644 (file)
@@ -1340,7 +1340,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
        }
 
        if (netif_is_bond_slave(nesvnic->netdev))
-               netdev = nesvnic->netdev->master;
+               netdev = netdev_master_upper_dev_get(nesvnic->netdev);
        else
                netdev = nesvnic->netdev;
 
index 9542e1644a5c1beff7559da4096d734912193209..85cf4d1ac4429898e039fb7c58ca805bb9fe9403 100644 (file)
@@ -1317,11 +1317,13 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
        struct nes_vnic *nesvnic = netdev_priv(netdev);
        struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
 
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
-       sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
-                               nesadapter->firmware_version & 0x000000ff);
-       strcpy(drvinfo->version, DRV_VERSION);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev),
+               sizeof(drvinfo->bus_info));
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+                "%u.%u", nesadapter->firmware_version >> 16,
+                nesadapter->firmware_version & 0x000000ff);
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
        drvinfo->testinfo_len = 0;
        drvinfo->eedump_len = 0;
        drvinfo->regdump_len = 0;
@@ -1703,7 +1705,6 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
        netdev->dev_addr[3] = (u8)(u64temp>>16);
        netdev->dev_addr[4] = (u8)(u64temp>>8);
        netdev->dev_addr[5] = (u8)u64temp;
-       memcpy(netdev->perm_addr, netdev->dev_addr, 6);
 
        netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX;
        if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV))
index 29bc7b5724aceb8746f8444fbbbae506abbea244..ca131335417b6e80c6b559f00ee22c53ed65bf9c 100644 (file)
@@ -39,7 +39,7 @@
 static void ipoib_get_drvinfo(struct net_device *netdev,
                              struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1);
+       strlcpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver));
 }
 
 static int ipoib_get_coalesce(struct net_device *dev,
index 5374c25f036cffa72b181a9286031696dbce4d0e..267dede13bfd458bac22310f28d1eb8e63575694 100644 (file)
@@ -22,13 +22,13 @@ MODULE_LICENSE("GPL");
 /****************************************/
 /* structure containing interface to hl */
 /****************************************/
-isdn_divert_if divert_if =
-{ DIVERT_IF_MAGIC,  /* magic value */
-  DIVERT_CMD_REG,   /* register cmd */
-  ll_callback,      /* callback routine from ll */
-  NULL,             /* command still not specified */
-  NULL,             /* drv_to_name */
-  NULL,             /* name_to_drv */
+isdn_divert_if divert_if = {
+       DIVERT_IF_MAGIC,        /* magic value */
+       DIVERT_CMD_REG,         /* register cmd */
+       ll_callback,            /* callback routine from ll */
+       NULL,                   /* command still not specified */
+       NULL,                   /* drv_to_name */
+       NULL,                   /* name_to_drv */
 };
 
 /*************************/
@@ -36,14 +36,15 @@ isdn_divert_if divert_if =
 /* no cmd line parms     */
 /*************************/
 static int __init divert_init(void)
-{ int i;
+{
+       int i;
 
-       if (divert_dev_init())
-       { printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
+       if (divert_dev_init()) {
+               printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
                return (-EIO);
        }
-       if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
-       { divert_dev_deinit();
+       if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
+               divert_dev_deinit();
                printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i);
                return (-EIO);
        }
@@ -61,13 +62,13 @@ static void __exit divert_exit(void)
 
        spin_lock_irqsave(&divert_lock, flags);
        divert_if.cmd = DIVERT_CMD_REL; /* release */
-       if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
-       { printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
+       if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
+               printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
                spin_unlock_irqrestore(&divert_lock, flags);
                return;
        }
-       if (divert_dev_deinit())
-       { printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
+       if (divert_dev_deinit()) {
+               printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
                spin_unlock_irqrestore(&divert_lock, flags);
                return;
        }
index e61e55f1f193fb54209c3e727caa8d4c0c541e4c..db432e635496d1b206f731832900eb17cad304d9 100644 (file)
@@ -19,8 +19,8 @@
 /**********************************/
 /* structure keeping calling info */
 /**********************************/
-struct call_struc
-{ isdn_ctrl ics; /* delivered setup + driver parameters */
+struct call_struc {
+       isdn_ctrl ics; /* delivered setup + driver parameters */
        ulong divert_id; /* Id delivered to user */
        unsigned char akt_state; /* actual state */
        char deflect_dest[35]; /* deflection destination */
@@ -34,8 +34,8 @@ struct call_struc
 /********************************************/
 /* structure keeping deflection table entry */
 /********************************************/
-struct deflect_struc
-{ struct deflect_struc *next, *prev;
+struct deflect_struc {
+       struct deflect_struc *next, *prev;
        divert_rule rule; /* used rule */
 };
 
@@ -64,16 +64,16 @@ static void deflect_timer_expire(ulong arg)
        del_timer(&cs->timer); /* delete active timer */
        spin_unlock_irqrestore(&divert_lock, flags);
 
-       switch (cs->akt_state)
-       case DEFLECT_PROCEED:
-                       cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
-                       divert_if.ll_cmd(&cs->ics);
-                       spin_lock_irqsave(&divert_lock, flags);
-                       cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
-                       cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
-                       add_timer(&cs->timer);
-                       spin_unlock_irqrestore(&divert_lock, flags);
-                       break;
+       switch (cs->akt_state) {
+       case DEFLECT_PROCEED:
+               cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
+               divert_if.ll_cmd(&cs->ics);
+               spin_lock_irqsave(&divert_lock, flags);
+               cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+               cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+               add_timer(&cs->timer);
+               spin_unlock_irqrestore(&divert_lock, flags);
+               break;
 
        case DEFLECT_ALERT:
                cs->ics.command = ISDN_CMD_REDIR; /* protocol */
@@ -111,7 +111,8 @@ static void deflect_timer_expire(ulong arg)
 int cf_command(int drvid, int mode,
               u_char proc, char *msn,
               u_char service, char *fwd_nr, ulong *procid)
-{ unsigned long flags;
+{
+       unsigned long flags;
        int retval, msnlen;
        int fwd_len;
        char *p, *ielenp, tmp[60];
@@ -130,8 +131,8 @@ int cf_command(int drvid, int mode,
        *p++ = 1;   /* length */
        *p++ = service; /* service to handle */
 
-       if (mode == 1)
-       { if (!*fwd_nr) return (-EINVAL); /* destination missing */
+       if (mode == 1) {
+               if (!*fwd_nr) return (-EINVAL); /* destination missing */
                if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */
                fwd_len = strlen(fwd_nr);
                *p++ = 0x30; /* number enumeration */
@@ -144,12 +145,12 @@ int cf_command(int drvid, int mode,
 
        msnlen = strlen(msn);
        *p++ = 0x80; /* msn number */
-       if (msnlen > 1)
-       { *p++ = msnlen; /* length */
+       if (msnlen > 1) {
+               *p++ = msnlen; /* length */
                strcpy(p, msn);
                p += msnlen;
-       }
-       else *p++ = 0;
+       } else
+               *p++ = 0;
 
        *ielenp = p - ielenp - 1; /* set total IE length */
 
@@ -186,14 +187,13 @@ int cf_command(int drvid, int mode,
 
        retval = divert_if.ll_cmd(&cs->ics); /* execute command */
 
-       if (!retval)
-       { cs->prev = NULL;
+       if (!retval) {
+               cs->prev = NULL;
                spin_lock_irqsave(&divert_lock, flags);
                cs->next = divert_head;
                divert_head = cs;
                spin_unlock_irqrestore(&divert_lock, flags);
-       }
-       else
+       } else
                kfree(cs);
        return (retval);
 } /* cf_command */
@@ -203,15 +203,16 @@ int cf_command(int drvid, int mode,
 /* handle a external deflection command */
 /****************************************/
 int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
-{ struct call_struc *cs;
+{
+       struct call_struc *cs;
        isdn_ctrl ic;
        unsigned long flags;
        int i;
 
        if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */
        cs = divert_head; /* start of parameter list */
-       while (cs)
-       { if (cs->divert_id == callid) break; /* found */
+       while (cs) {
+               if (cs->divert_id == callid) break; /* found */
                cs = cs->next;
        } /* search entry */
        if (!cs) return (-EINVAL); /* invalid callid */
@@ -220,32 +221,30 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
        ic.arg = cs->ics.arg;
        i = -EINVAL;
        if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */
-       switch (cmd & 0x7F)
-       case 0: /* hangup */
-                       del_timer(&cs->timer);
-                       ic.command = ISDN_CMD_HANGUP;
-                       i = divert_if.ll_cmd(&ic);
-                       spin_lock_irqsave(&divert_lock, flags);
-                       cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
-                       cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
-                       add_timer(&cs->timer);
-                       spin_unlock_irqrestore(&divert_lock, flags);
-                       break;
+       switch (cmd & 0x7F) {
+       case 0: /* hangup */
+               del_timer(&cs->timer);
+               ic.command = ISDN_CMD_HANGUP;
+               i = divert_if.ll_cmd(&ic);
+               spin_lock_irqsave(&divert_lock, flags);
+               cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+               cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+               add_timer(&cs->timer);
+               spin_unlock_irqrestore(&divert_lock, flags);
+               break;
 
        case 1: /* alert */
                if (cs->akt_state == DEFLECT_ALERT) return (0);
                cmd &= 0x7F; /* never wait */
                del_timer(&cs->timer);
                ic.command = ISDN_CMD_ALERT;
-               if ((i = divert_if.ll_cmd(&ic)))
-               {
+               if ((i = divert_if.ll_cmd(&ic))) {
                        spin_lock_irqsave(&divert_lock, flags);
                        cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
                        cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
                        add_timer(&cs->timer);
                        spin_unlock_irqrestore(&divert_lock, flags);
-               }
-               else
+               } else
                        cs->akt_state = DEFLECT_ALERT;
                break;
 
@@ -254,15 +253,13 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
                strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
                strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
                ic.command = ISDN_CMD_REDIR;
-               if ((i = divert_if.ll_cmd(&ic)))
-               {
+               if ((i = divert_if.ll_cmd(&ic))) {
                        spin_lock_irqsave(&divert_lock, flags);
                        cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
                        cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
                        add_timer(&cs->timer);
                        spin_unlock_irqrestore(&divert_lock, flags);
-               }
-               else
+               } else
                        cs->akt_state = DEFLECT_ALERT;
                break;
 
@@ -274,19 +271,19 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
 /* insert a new rule before idx */
 /********************************/
 int insertrule(int idx, divert_rule *newrule)
-{ struct deflect_struc *ds, *ds1 = NULL;
+{
+       struct deflect_struc *ds, *ds1 = NULL;
        unsigned long flags;
 
-       if (!(ds = kmalloc(sizeof(struct deflect_struc),
-                          GFP_KERNEL)))
+       if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL)))
                return (-ENOMEM); /* no memory */
 
        ds->rule = *newrule; /* set rule */
 
        spin_lock_irqsave(&divert_lock, flags);
 
-       if (idx >= 0)
-       { ds1 = table_head;
+       if (idx >= 0) {
+               ds1 = table_head;
                while ((ds1) && (idx > 0))
                { idx--;
                        ds1 = ds1->next;
@@ -294,17 +291,16 @@ int insertrule(int idx, divert_rule *newrule)
                if (!ds1) idx = -1;
        }
 
-       if (idx < 0)
-       { ds->prev = table_tail; /* previous entry */
+       if (idx < 0) {
+               ds->prev = table_tail; /* previous entry */
                ds->next = NULL; /* end of chain */
                if (ds->prev)
                        ds->prev->next = ds; /* last forward */
                else
                        table_head = ds; /* is first entry */
                table_tail = ds; /* end of queue */
-       }
-       else
-       { ds->next = ds1; /* next entry */
+       } else {
+               ds->next = ds1; /* next entry */
                ds->prev = ds1->prev; /* prev entry */
                ds1->prev = ds; /* backward chain old element */
                if (!ds->prev)
@@ -319,17 +315,18 @@ int insertrule(int idx, divert_rule *newrule)
 /* delete the rule at position idx */
 /***********************************/
 int deleterule(int idx)
-{ struct deflect_struc *ds, *ds1;
+{
+       struct deflect_struc *ds, *ds1;
        unsigned long flags;
 
-       if (idx < 0)
-       { spin_lock_irqsave(&divert_lock, flags);
+       if (idx < 0) {
+               spin_lock_irqsave(&divert_lock, flags);
                ds = table_head;
                table_head = NULL;
                table_tail = NULL;
                spin_unlock_irqrestore(&divert_lock, flags);
-               while (ds)
-               { ds1 = ds;
+               while (ds) {
+                       ds1 = ds;
                        ds = ds->next;
                        kfree(ds1);
                }
@@ -339,13 +336,12 @@ int deleterule(int idx)
        spin_lock_irqsave(&divert_lock, flags);
        ds = table_head;
 
-       while ((ds) && (idx > 0))
-       { idx--;
+       while ((ds) && (idx > 0)) {
+               idx--;
                ds = ds->next;
        }
 
-       if (!ds)
-       {
+       if (!ds) {
                spin_unlock_irqrestore(&divert_lock, flags);
                return (-EINVAL);
        }
@@ -369,12 +365,13 @@ int deleterule(int idx)
 /* get a pointer to a specific rule number */
 /*******************************************/
 divert_rule *getruleptr(int idx)
-{ struct deflect_struc *ds = table_head;
+{
+       struct deflect_struc *ds = table_head;
 
        if (idx < 0) return (NULL);
-       while ((ds) && (idx >= 0))
-       { if (!(idx--))
-               { return (&ds->rule);
+       while ((ds) && (idx >= 0)) {
+               if (!(idx--)) {
+                       return (&ds->rule);
                        break;
                }
                ds = ds->next;
@@ -386,7 +383,8 @@ divert_rule *getruleptr(int idx)
 /* called from common module on an incoming call */
 /*************************************************/
 static int isdn_divert_icall(isdn_ctrl *ic)
-{ int retval = 0;
+{
+       int retval = 0;
        unsigned long flags;
        struct call_struc *cs = NULL;
        struct deflect_struc *dv;
@@ -394,8 +392,8 @@ static int isdn_divert_icall(isdn_ctrl *ic)
        u_char accept;
 
        /* first check the internal deflection table */
-       for (dv = table_head; dv; dv = dv->next)
-       { /* scan table */
+       for (dv = table_head; dv; dv = dv->next) {
+               /* scan table */
                if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
                    ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
                        continue; /* call option check */
@@ -409,10 +407,10 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                p = dv->rule.my_msn;
                p1 = ic->parm.setup.eazmsn;
                accept = 0;
-               while (*p)
-               { /* complete compare */
-                       if (*p == '-')
-                       { accept = 1; /* call accepted */
+               while (*p) {
+                       /* complete compare */
+                       if (*p == '-') {
+                               accept = 1; /* call accepted */
                                break;
                        }
                        if (*p++ != *p1++)
@@ -422,14 +420,15 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                } /* complete compare */
                if (!accept) continue; /* not accepted */
 
-               if ((strcmp(dv->rule.caller, "0")) || (ic->parm.setup.phone[0]))
-               { p = dv->rule.caller;
+               if ((strcmp(dv->rule.caller, "0")) ||
+                   (ic->parm.setup.phone[0])) {
+                       p = dv->rule.caller;
                        p1 = ic->parm.setup.phone;
                        accept = 0;
-                       while (*p)
-                       { /* complete compare */
-                               if (*p == '-')
-                               { accept = 1; /* call accepted */
+                       while (*p) {
+                               /* complete compare */
+                               if (*p == '-') {
+                                       accept = 1; /* call accepted */
                                        break;
                                }
                                if (*p++ != *p1++)
@@ -440,10 +439,10 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                        if (!accept) continue; /* not accepted */
                }
 
-               switch (dv->rule.action)
-               case DEFLECT_IGNORE:
-                               return (0);
-                               break;
+               switch (dv->rule.action) {
+               case DEFLECT_IGNORE:
+                       return (0);
+                       break;
 
                case DEFLECT_ALERT:
                case DEFLECT_PROCEED:
@@ -465,31 +464,29 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                        cs->ics.parm.setup.screen = dv->rule.screen;
                        if (dv->rule.waittime)
                                cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
+                       else if (dv->rule.action == DEFLECT_PROCEED)
+                               cs->timer.expires = jiffies + (HZ * extern_wait_max);
                        else
-                               if (dv->rule.action == DEFLECT_PROCEED)
-                                       cs->timer.expires = jiffies + (HZ * extern_wait_max);
-                               else
-                                       cs->timer.expires = 0;
+                               cs->timer.expires = 0;
                        cs->akt_state = dv->rule.action;
                        spin_lock_irqsave(&divert_lock, flags);
                        cs->divert_id = next_id++; /* new sequence number */
                        spin_unlock_irqrestore(&divert_lock, flags);
                        cs->prev = NULL;
-                       if (cs->akt_state == DEFLECT_ALERT)
-                       { strcpy(cs->deflect_dest, dv->rule.to_nr);
-                               if (!cs->timer.expires)
-                               { strcpy(ic->parm.setup.eazmsn, "Testtext direct");
+                       if (cs->akt_state == DEFLECT_ALERT) {
+                               strcpy(cs->deflect_dest, dv->rule.to_nr);
+                               if (!cs->timer.expires) {
+                                       strcpy(ic->parm.setup.eazmsn,
+                                              "Testtext direct");
                                        ic->parm.setup.screen = dv->rule.screen;
                                        strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
                                        cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
                                        cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
                                        retval = 5;
-                               }
-                               else
+                               } else
                                        retval = 1; /* alerting */
-                       }
-                       else
-                       { cs->deflect_dest[0] = '\0';
+                       } else {
+                               cs->deflect_dest[0] = '\0';
                                retval = 4; /* only proceed */
                        }
                        sprintf(cs->info, "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
@@ -505,8 +502,8 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                                dv->rule.waittime,
                                cs->deflect_dest);
                        if ((dv->rule.action == DEFLECT_REPORT) ||
-                           (dv->rule.action == DEFLECT_REJECT))
-                       { put_info_buffer(cs->info);
+                           (dv->rule.action == DEFLECT_REJECT)) {
+                               put_info_buffer(cs->info);
                                kfree(cs); /* remove */
                                return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
                        }
@@ -519,8 +516,8 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                break;
        } /* scan_table */
 
-       if (cs)
-       { cs->prev = NULL;
+       if (cs) {
+               cs->prev = NULL;
                spin_lock_irqsave(&divert_lock, flags);
                cs->next = divert_head;
                divert_head = cs;
@@ -529,21 +526,21 @@ static int isdn_divert_icall(isdn_ctrl *ic)
 
                put_info_buffer(cs->info);
                return (retval);
-       }
-       else
+       } else
                return (0);
 } /* isdn_divert_icall */
 
 
 void deleteprocs(void)
-{ struct call_struc *cs, *cs1;
+{
+       struct call_struc *cs, *cs1;
        unsigned long flags;
 
        spin_lock_irqsave(&divert_lock, flags);
        cs = divert_head;
        divert_head = NULL;
-       while (cs)
-       { del_timer(&cs->timer);
+       while (cs) {
+               del_timer(&cs->timer);
                cs1 = cs;
                cs = cs->next;
                kfree(cs1);
@@ -555,12 +552,13 @@ void deleteprocs(void)
 /* put a address including address type into buffer */
 /****************************************************/
 static int put_address(char *st, u_char *p, int len)
-{ u_char retval = 0;
+{
+       u_char retval = 0;
        u_char adr_typ = 0; /* network standard */
 
        if (len < 2) return (retval);
-       if (*p == 0xA1)
-       { retval = *(++p) + 2; /* total length */
+       if (*p == 0xA1) {
+               retval = *(++p) + 2; /* total length */
                if (retval > len) return (0); /* too short */
                len = retval - 2; /* remaining length */
                if (len < 3) return (0);
@@ -572,16 +570,13 @@ static int put_address(char *st, u_char *p, int len)
                if (*p++ != 0x12) return (0);
                if (*p > len) return (0); /* check number length */
                len = *p++;
-       }
-       else
-               if (*p == 0x80)
-               { retval = *(++p) + 2; /* total length */
-                       if (retval > len) return (0);
-                       len = retval - 2;
-                       p++;
-               }
-               else
-                       return (0); /* invalid address information */
+       } else if (*p == 0x80) {
+               retval = *(++p) + 2; /* total length */
+               if (retval > len) return (0);
+               len = retval - 2;
+               p++;
+       } else
+               return (0); /* invalid address information */
 
        sprintf(st, "%d ", adr_typ);
        st += strlen(st);
@@ -598,7 +593,8 @@ static int put_address(char *st, u_char *p, int len)
 /* report a successful interrogation */
 /*************************************/
 static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
-{ char *src = ic->parm.dss1_io.data;
+{
+       char *src = ic->parm.dss1_io.data;
        int restlen = ic->parm.dss1_io.datalen;
        int cnt = 1;
        u_char n, n1;
@@ -608,50 +604,44 @@ static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
        if (*src++ != 0x30) return (-101);
        if ((n = *src++) > 0x81) return (-102); /* invalid length field */
        restlen -= 2; /* remaining bytes */
-       if (n == 0x80)
-       { if (restlen < 2) return (-103);
+       if (n == 0x80) {
+               if (restlen < 2) return (-103);
                if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104);
                restlen -= 2;
-       }
+       } else if (n == 0x81) {
+               n = *src++;
+               restlen--;
+               if (n > restlen) return (-105);
+               restlen = n;
+       } else if (n > restlen)
+               return (-106);
        else
-               if (n == 0x81)
-               { n = *src++;
-                       restlen--;
-                       if (n > restlen) return (-105);
-                       restlen = n;
-               }
-               else
-                       if (n > restlen) return (-106);
-                       else
-                               restlen = n; /* standard format */
+               restlen = n; /* standard format */
        if (restlen < 3) return (-107); /* no procedure */
        if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108);
        restlen -= 3;
        if (restlen < 2) return (-109); /* list missing */
-       if (*src == 0x31)
-       { src++;
+       if (*src == 0x31) {
+               src++;
                if ((n = *src++) > 0x81) return (-110); /* invalid length field */
                restlen -= 2; /* remaining bytes */
-               if (n == 0x80)
-               { if (restlen < 2) return (-111);
+               if (n == 0x80) {
+                       if (restlen < 2) return (-111);
                        if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112);
                        restlen -= 2;
-               }
+               } else if (n == 0x81) {
+                       n = *src++;
+                       restlen--;
+                       if (n > restlen) return (-113);
+                       restlen = n;
+               } else if (n > restlen)
+                       return (-114);
                else
-                       if (n == 0x81)
-                       { n = *src++;
-                               restlen--;
-                               if (n > restlen) return (-113);
-                               restlen = n;
-                       }
-                       else
-                               if (n > restlen) return (-114);
-                               else
-                                       restlen = n; /* standard format */
+                       restlen = n; /* standard format */
        } /* result list header */
 
-       while (restlen >= 2)
-       { stp = st;
+       while (restlen >= 2) {
+               stp = st;
                sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id,
                        cnt++, divert_if.drv_to_name(ic->driver));
                stp += strlen(stp);
@@ -674,8 +664,8 @@ static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
                sprintf(stp, "%d ", (*p++) & 0xFF);
                stp += strlen(stp);
                n -= 6;
-               if (n > 2)
-               { if (*p++ != 0x30) continue;
+               if (n > 2) {
+                       if (*p++ != 0x30) continue;
                        if (*p > (n - 2)) continue;
                        n = *p++;
                        if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
@@ -692,58 +682,58 @@ static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
 /* callback for protocol specific extensions */
 /*********************************************/
 static int prot_stat_callback(isdn_ctrl *ic)
-{ struct call_struc *cs, *cs1;
+{
+       struct call_struc *cs, *cs1;
        int i;
        unsigned long flags;
 
        cs = divert_head; /* start of list */
        cs1 = NULL;
-       while (cs)
-       { if (ic->driver == cs->ics.driver)
-               { switch (cs->ics.arg)
-                       { case DSS1_CMD_INVOKE:
-                                       if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
-                                           (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
-                                       { switch (ic->arg)
-                                               {  case DSS1_STAT_INVOKE_ERR:
-                                                               sprintf(cs->info, "128 0x%lx 0x%x\n",
-                                                                       ic->parm.dss1_io.ll_id,
-                                                                       ic->parm.dss1_io.timeout);
-                                                               put_info_buffer(cs->info);
-                                                               break;
-
-                                               case DSS1_STAT_INVOKE_RES:
-                                                       switch (cs->ics.parm.dss1_io.proc)
-                                                       {  case  7:
-                                                       case  8:
-                                                               put_info_buffer(cs->info);
-                                                               break;
-
-                                                       case  11:
-                                                               i = interrogate_success(ic, cs);
-                                                               if (i)
-                                                                       sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
-                                                                               ic->parm.dss1_io.ll_id, i);
-                                                               put_info_buffer(cs->info);
-                                                               break;
-
-                                                       default:
-                                                               printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
-                                                               break;
-                                                       }
-
+       while (cs) {
+               if (ic->driver == cs->ics.driver) {
+                       switch (cs->ics.arg) {
+                       case DSS1_CMD_INVOKE:
+                               if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
+                                   (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) {
+                                       switch (ic->arg) {
+                                       case DSS1_STAT_INVOKE_ERR:
+                                               sprintf(cs->info, "128 0x%lx 0x%x\n",
+                                                       ic->parm.dss1_io.ll_id,
+                                                       ic->parm.dss1_io.timeout);
+                                               put_info_buffer(cs->info);
+                                               break;
+
+                                       case DSS1_STAT_INVOKE_RES:
+                                               switch (cs->ics.parm.dss1_io.proc) {
+                                               case  7:
+                                               case  8:
+                                                       put_info_buffer(cs->info);
+                                                       break;
 
+                                               case  11:
+                                                       i = interrogate_success(ic, cs);
+                                                       if (i)
+                                                               sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
+                                                                       ic->parm.dss1_io.ll_id, i);
+                                                       put_info_buffer(cs->info);
                                                        break;
 
                                                default:
-                                                       printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
+                                                       printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
                                                        break;
                                                }
-                                               cs1 = cs; /* remember structure */
-                                               cs = NULL;
-                                               continue; /* abort search */
-                                       } /* id found */
-                                       break;
+
+                                               break;
+
+                                       default:
+                                               printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
+                                               break;
+                                       }
+                                       cs1 = cs; /* remember structure */
+                                       cs = NULL;
+                                       continue; /* abort search */
+                               } /* id found */
+                               break;
 
                        case DSS1_CMD_INVOKE_ABORT:
                                printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
@@ -757,13 +747,12 @@ static int prot_stat_callback(isdn_ctrl *ic)
                } /* driver ok */
        }
 
-       if (!cs1)
-       { printk(KERN_WARNING "dss1_divert unhandled process\n");
+       if (!cs1) {
+               printk(KERN_WARNING "dss1_divert unhandled process\n");
                return (0);
        }
 
-       if (cs1->ics.driver == -1)
-       {
+       if (cs1->ics.driver == -1) {
                spin_lock_irqsave(&divert_lock, flags);
                del_timer(&cs1->timer);
                if (cs1->prev)
@@ -784,20 +773,22 @@ static int prot_stat_callback(isdn_ctrl *ic)
 /* status callback from HL */
 /***************************/
 static int isdn_divert_stat_callback(isdn_ctrl *ic)
-{ struct call_struc *cs, *cs1;
+{
+       struct call_struc *cs, *cs1;
        unsigned long flags;
        int retval;
 
        retval = -1;
        cs = divert_head; /* start of list */
-       while (cs)
-       { if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
-               { switch (ic->command)
-                       { case ISDN_STAT_DHUP:
-                                       sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
-                                       del_timer(&cs->timer);
-                                       cs->ics.driver = -1;
-                                       break;
+       while (cs) {
+               if ((ic->driver == cs->ics.driver) &&
+                   (ic->arg == cs->ics.arg)) {
+                       switch (ic->command) {
+                       case ISDN_STAT_DHUP:
+                               sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
+                               del_timer(&cs->timer);
+                               cs->ics.driver = -1;
+                               break;
 
                        case ISDN_STAT_CAUSE:
                                sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num);
@@ -818,8 +809,7 @@ static int isdn_divert_stat_callback(isdn_ctrl *ic)
                }
                cs1 = cs;
                cs = cs->next;
-               if (cs1->ics.driver == -1)
-               {
+               if (cs1->ics.driver == -1) {
                        spin_lock_irqsave(&divert_lock, flags);
                        if (cs1->prev)
                                cs1->prev->next = cs1->next; /* forward link */
@@ -840,20 +830,19 @@ static int isdn_divert_stat_callback(isdn_ctrl *ic)
 /********************/
 int ll_callback(isdn_ctrl *ic)
 {
-       switch (ic->command)
-       case ISDN_STAT_ICALL:
+       switch (ic->command) {
+       case ISDN_STAT_ICALL:
        case ISDN_STAT_ICALLW:
                return (isdn_divert_icall(ic));
                break;
 
        case ISDN_STAT_PROT:
-               if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
-               { if (ic->arg != DSS1_STAT_INVOKE_BRD)
+               if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) {
+                       if (ic->arg != DSS1_STAT_INVOKE_BRD)
                                return (prot_stat_callback(ic));
                        else
                                return (0); /* DSS1 invoke broadcast */
-               }
-               else
+               } else
                        return (-1); /* protocol not euro */
 
        default:
index 42f289320d2d2961fbd2dac1b8ac498da286fa46..55033dd872c0258b4902e3056e3563d273770793 100644 (file)
@@ -43,8 +43,8 @@
 
 #define DEFLECT_ALL_IDS   0xFFFFFFFF /* all drivers selected */
 
-typedef struct
-{ ulong drvid;     /* driver ids, bit mapped */
+typedef struct {
+       ulong drvid;     /* driver ids, bit mapped */
        char my_msn[35]; /* desired msn, subaddr allowed */
        char caller[35]; /* caller id, partial string with * + subaddr allowed */
        char to_nr[35];  /* deflected to number incl. subaddress */
@@ -65,18 +65,18 @@ typedef struct
        u_char waittime; /* maximum wait time for proceeding */
 } divert_rule;
 
-typedef union
-{ int drv_version; /* return of driver version */
-       struct
-       { int drvid;            /* id of driver */
+typedef union {
+       int drv_version; /* return of driver version */
+       struct {
+               int drvid;              /* id of driver */
                char drvnam[30];        /* name of driver */
        } getid;
-       struct
-       { int ruleidx;  /* index of rule */
+       struct {
+               int ruleidx;    /* index of rule */
                divert_rule rule;       /* rule parms */
        } getsetrule;
-       struct
-       { u_char subcmd;  /* 0 = hangup/reject,
+       struct {
+               u_char subcmd;  /* 0 = hangup/reject,
                             1 = alert,
                             2 = deflect */
                ulong callid;   /* id of call delivered by ascii output */
@@ -84,8 +84,8 @@ typedef union
                                   else uus1 string (maxlen 31),
                                   data from rule used if empty */
        } fwd_ctrl;
-       struct
-       { int drvid;      /* id of driver */
+       struct {
+               int drvid;      /* id of driver */
                u_char cfproc;  /* cfu = 0, cfb = 1, cfnr = 2 */
                ulong procid;   /* process id returned when no error */
                u_char service; /* basically coded service, 0 = all */
@@ -104,8 +104,8 @@ typedef union
 /**************************************************/
 /* structure keeping ascii info for device output */
 /**************************************************/
-struct divert_info
-{ struct divert_info *next;
+struct divert_info {
+       struct divert_info *next;
        ulong usage_cnt; /* number of files still to work */
        char info_start[2]; /* info string start */
 };
index 6849a11a1b246f5e9ab4bb876efdcf5397fc6c4c..7c7814497e3ea28587f208b98da95ece812a25a1 100644 (file)
@@ -467,11 +467,6 @@ void gigaset_freecs(struct cardstate *cs)
 
        mutex_lock(&cs->mutex);
 
-       if (!cs->bcs)
-               goto f_cs;
-       if (!cs->inbuf)
-               goto f_bcs;
-
        spin_lock_irqsave(&cs->lock, flags);
        cs->running = 0;
        spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
@@ -507,17 +502,16 @@ void gigaset_freecs(struct cardstate *cs)
                gig_dbg(DEBUG_INIT, "clearing at_state");
                clear_at_state(&cs->at_state);
                dealloc_temp_at_states(cs);
+               clear_events(cs);
                tty_port_destroy(&cs->port);
 
                /* fall through */
        case 0: /* error in basic setup */
-               clear_events(cs);
                gig_dbg(DEBUG_INIT, "freeing inbuf");
                kfree(cs->inbuf);
+               kfree(cs->bcs);
        }
-f_bcs: gig_dbg(DEBUG_INIT, "freeing bcs[]");
-       kfree(cs->bcs);
-f_cs:  gig_dbg(DEBUG_INIT, "freeing cs");
+
        mutex_unlock(&cs->mutex);
        free_cs(cs);
 }
@@ -687,19 +681,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
                return NULL;
        }
 
-       gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
-       cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
-       if (!cs->bcs) {
-               pr_err("out of memory\n");
-               goto error;
-       }
-       gig_dbg(DEBUG_INIT, "allocating inbuf");
-       cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
-       if (!cs->inbuf) {
-               pr_err("out of memory\n");
-               goto error;
-       }
-
        cs->cs_init = 0;
        cs->channels = channels;
        cs->onechannel = onechannel;
@@ -729,6 +710,12 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
        cs->mode = M_UNKNOWN;
        cs->mstate = MS_UNINITIALIZED;
 
+       cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
+       cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
+       if (!cs->bcs || !cs->inbuf) {
+               pr_err("out of memory\n");
+               goto error;
+       }
        ++cs->cs_init;
 
        gig_dbg(DEBUG_INIT, "setting up at_state");
index 2e6963dc740ea340778094ed3cab25e3b1d2ddaa..7459b127ddd59fe00fd2872337c2c8eb5845f7d5 100644 (file)
@@ -351,10 +351,11 @@ struct reply_t gigaset_tab_cid[] =
 
 
 static const struct resp_type_t {
-       unsigned char   *response;
-       int             resp_code;
-       int             type;
-} resp_type[] =
+       char    *response;
+       int     resp_code;
+       int     type;
+}
+resp_type[] =
 {
        {"OK",          RSP_OK,         RT_NOTHING},
        {"ERROR",       RSP_ERROR,      RT_NOTHING},
@@ -374,11 +375,12 @@ static const struct resp_type_t {
 };
 
 static const struct zsau_resp_t {
-       unsigned char   *str;
-       int             code;
-} zsau_resp[] =
+       char    *str;
+       int     code;
+}
+zsau_resp[] =
 {
-       {"OUTGOING_CALL_PROCEEDING",    ZSAU_OUTGOING_CALL_PROCEEDING},
+       {"OUTGOING_CALL_PROCEEDING",    ZSAU_PROCEEDING},
        {"CALL_DELIVERED",              ZSAU_CALL_DELIVERED},
        {"ACTIVE",                      ZSAU_ACTIVE},
        {"DISCONNECT_IND",              ZSAU_DISCONNECT_IND},
@@ -434,7 +436,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
        len = cs->cbytes;
        if (!len) {
                /* ignore additional LFs/CRs (M10x config mode or cx100) */
-               gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]);
+               gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[0]);
                return;
        }
        cs->respdata[len] = 0;
@@ -707,27 +709,29 @@ static void schedule_init(struct cardstate *cs, int state)
        cs->commands_pending = 1;
 }
 
-/* Add "AT" to a command, add the cid, dle encode it, send the result to the
-   hardware. */
-static void send_command(struct cardstate *cs, const char *cmd, int cid,
-                        int dle, gfp_t kmallocflags)
+/* send an AT command
+ * adding the "AT" prefix, cid and DLE encapsulation as appropriate
+ */
+static void send_command(struct cardstate *cs, const char *cmd,
+                        struct at_state_t *at_state)
 {
+       int cid = at_state->cid;
        struct cmdbuf_t *cb;
        size_t buflen;
 
        buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */
-       cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, kmallocflags);
+       cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, GFP_ATOMIC);
        if (!cb) {
                dev_err(cs->dev, "%s: out of memory\n", __func__);
                return;
        }
        if (cid > 0 && cid <= 65535)
                cb->len = snprintf(cb->buf, buflen,
-                                  dle ? "\020(AT%d%s\020)" : "AT%d%s",
+                                  cs->dle ? "\020(AT%d%s\020)" : "AT%d%s",
                                   cid, cmd);
        else
                cb->len = snprintf(cb->buf, buflen,
-                                  dle ? "\020(AT%s\020)" : "AT%s",
+                                  cs->dle ? "\020(AT%s\020)" : "AT%s",
                                   cmd);
        cb->offset = 0;
        cb->next = NULL;
@@ -886,7 +890,7 @@ static void finish_shutdown(struct cardstate *cs)
                gigaset_isdn_stop(cs);
        }
 
-       /* The rest is done by cleanup_cs () in user mode. */
+       /* The rest is done by cleanup_cs() in process context. */
 
        cs->cmd_result = -ENODEV;
        cs->waiting = 0;
@@ -976,10 +980,9 @@ exit:
 }
 
 static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
-                        struct at_state_t **p_at_state)
+                        struct at_state_t *at_state)
 {
        int retval;
-       struct at_state_t *at_state = *p_at_state;
 
        retval = gigaset_isdn_icall(at_state);
        switch (retval) {
@@ -1176,7 +1179,7 @@ static void do_action(int action, struct cardstate *cs,
                spin_unlock_irqrestore(&cs->lock, flags);
                break;
        case ACT_ICALL:
-               handle_icall(cs, bcs, p_at_state);
+               handle_icall(cs, bcs, at_state);
                break;
        case ACT_FAILSDOWN:
                dev_warn(cs->dev, "Could not shut down the device.\n");
@@ -1264,7 +1267,7 @@ static void do_action(int action, struct cardstate *cs,
                        cs->commands_pending = 1;
                        break;
                }
-               /* fall through */
+               /* bad cid: fall through */
        case ACT_FAILCID:
                cs->cur_at_seq = SEQ_NONE;
                channel = cs->curchannel;
@@ -1339,7 +1342,6 @@ static void do_action(int action, struct cardstate *cs,
                        *p_resp_code = RSP_ERROR;
                        break;
                }
-               /*at_state->getstring = 1;*/
                cs->gotfwver = 0;
                break;
        case ACT_GOTVER:
@@ -1471,7 +1473,6 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
        int rcode;
        int genresp = 0;
        int resp_code = RSP_ERROR;
-       int sendcid;
        struct at_state_t *at_state;
        int index;
        int curact;
@@ -1499,7 +1500,6 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
                at_state->ConState, ev->type);
 
        bcs = at_state->bcs;
-       sendcid = at_state->cid;
 
        /* Setting the pointer to the dial array */
        rep = at_state->replystruct;
@@ -1510,10 +1510,12 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
                    || !at_state->timer_active) {
                        ev->type = RSP_NONE; /* old timeout */
                        gig_dbg(DEBUG_EVENT, "old timeout");
-               } else if (!at_state->waiting)
-                       gig_dbg(DEBUG_EVENT, "timeout occurred");
-               else
-                       gig_dbg(DEBUG_EVENT, "stopped waiting");
+               } else {
+                       if (at_state->waiting)
+                               gig_dbg(DEBUG_EVENT, "stopped waiting");
+                       else
+                               gig_dbg(DEBUG_EVENT, "timeout occurred");
+               }
        }
        spin_unlock_irqrestore(&cs->lock, flags);
 
@@ -1561,45 +1563,40 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
                do_action(rep->action[curact], cs, bcs, &at_state, &p_command,
                          &genresp, &resp_code, ev);
                if (!at_state)
-                       break; /* may be freed after disconnect */
+                       /* at_state destroyed by disconnect */
+                       return;
        }
 
-       if (at_state) {
-               /* Jump to the next con-state regarding the array */
-               if (rep->new_ConState >= 0)
-                       at_state->ConState = rep->new_ConState;
+       /* Jump to the next con-state regarding the array */
+       if (rep->new_ConState >= 0)
+               at_state->ConState = rep->new_ConState;
 
-               if (genresp) {
-                       spin_lock_irqsave(&cs->lock, flags);
+       if (genresp) {
+               spin_lock_irqsave(&cs->lock, flags);
+               at_state->timer_expires = 0;
+               at_state->timer_active = 0;
+               spin_unlock_irqrestore(&cs->lock, flags);
+               gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL);
+       } else {
+               /* Send command to modem if not NULL... */
+               if (p_command) {
+                       if (cs->connected)
+                               send_command(cs, p_command, at_state);
+                       else
+                               gigaset_add_event(cs, at_state, RSP_NODEV,
+                                                 NULL, 0, NULL);
+               }
+
+               spin_lock_irqsave(&cs->lock, flags);
+               if (!rep->timeout) {
                        at_state->timer_expires = 0;
                        at_state->timer_active = 0;
-                       spin_unlock_irqrestore(&cs->lock, flags);
-                       gigaset_add_event(cs, at_state, resp_code,
-                                         NULL, 0, NULL);
-               } else {
-                       /* Send command to modem if not NULL... */
-                       if (p_command) {
-                               if (cs->connected)
-                                       send_command(cs, p_command,
-                                                    sendcid, cs->dle,
-                                                    GFP_ATOMIC);
-                               else
-                                       gigaset_add_event(cs, at_state,
-                                                         RSP_NODEV,
-                                                         NULL, 0, NULL);
-                       }
-
-                       spin_lock_irqsave(&cs->lock, flags);
-                       if (!rep->timeout) {
-                               at_state->timer_expires = 0;
-                               at_state->timer_active = 0;
-                       } else if (rep->timeout > 0) { /* new timeout */
-                               at_state->timer_expires = rep->timeout * 10;
-                               at_state->timer_active = 1;
-                               ++at_state->timer_index;
-                       }
-                       spin_unlock_irqrestore(&cs->lock, flags);
+               } else if (rep->timeout > 0) { /* new timeout */
+                       at_state->timer_expires = rep->timeout * 10;
+                       at_state->timer_active = 1;
+                       ++at_state->timer_index;
                }
+               spin_unlock_irqrestore(&cs->lock, flags);
        }
 }
 
@@ -1693,6 +1690,11 @@ static void process_command_flags(struct cardstate *cs)
        for (i = 0; i < cs->channels; ++i) {
                bcs = cs->bcs + i;
                if (bcs->at_state.pending_commands & PC_HUP) {
+                       if (cs->dle) {
+                               cs->curchannel = bcs->channel;
+                               schedule_sequence(cs, &cs->at_state, SEQ_DLE0);
+                               return;
+                       }
                        bcs->at_state.pending_commands &= ~PC_HUP;
                        if (bcs->at_state.pending_commands & PC_CID) {
                                /* not yet dialing: PC_NOCID is sufficient */
index 8e2fc8f31d16455885177deb2c55b9a9b56c32a9..eb63a0f7a02a94191ef54c54740c778ece40a2cf 100644 (file)
@@ -111,11 +111,10 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
 
 /* connection state */
 #define ZSAU_NONE                      0
-#define ZSAU_DISCONNECT_IND            4
-#define ZSAU_OUTGOING_CALL_PROCEEDING  1
 #define ZSAU_PROCEEDING                        1
 #define ZSAU_CALL_DELIVERED            2
 #define ZSAU_ACTIVE                    3
+#define ZSAU_DISCONNECT_IND            4
 #define ZSAU_NULL                      5
 #define ZSAU_DISCONNECT_REQ            6
 #define ZSAU_UNKNOWN                   -1
@@ -183,18 +182,22 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
 #define AT_NUM         7
 
 /* variables in struct at_state_t */
+/* - numeric */
 #define VAR_ZSAU       0
 #define VAR_ZDLE       1
 #define VAR_ZCTP       2
+/* total number */
 #define VAR_NUM                3
-
+/* - string */
 #define STR_NMBR       0
 #define STR_ZCPN       1
 #define STR_ZCON       2
 #define STR_ZBC                3
 #define STR_ZHLC       4
+/* total number */
 #define STR_NUM                5
 
+/* event types */
 #define EV_TIMEOUT     -105
 #define EV_IF_VER      -106
 #define EV_PROC_CIDMODE        -107
index 67abf3ff45e812eec6ce416a917cacec5a650b39..20b7e7a1190f317bbf31d072c809ab70e919514b 100644 (file)
@@ -112,36 +112,6 @@ static int if_config(struct cardstate *cs, int *arg)
 }
 
 /*** the terminal driver ***/
-/* stolen from usbserial and some other tty drivers */
-
-static int  if_open(struct tty_struct *tty, struct file *filp);
-static void if_close(struct tty_struct *tty, struct file *filp);
-static int  if_ioctl(struct tty_struct *tty,
-                    unsigned int cmd, unsigned long arg);
-static int  if_write_room(struct tty_struct *tty);
-static int  if_chars_in_buffer(struct tty_struct *tty);
-static void if_throttle(struct tty_struct *tty);
-static void if_unthrottle(struct tty_struct *tty);
-static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
-static int  if_tiocmget(struct tty_struct *tty);
-static int  if_tiocmset(struct tty_struct *tty,
-                       unsigned int set, unsigned int clear);
-static int  if_write(struct tty_struct *tty,
-                    const unsigned char *buf, int count);
-
-static const struct tty_operations if_ops = {
-       .open =                 if_open,
-       .close =                if_close,
-       .ioctl =                if_ioctl,
-       .write =                if_write,
-       .write_room =           if_write_room,
-       .chars_in_buffer =      if_chars_in_buffer,
-       .set_termios =          if_set_termios,
-       .throttle =             if_throttle,
-       .unthrottle =           if_unthrottle,
-       .tiocmget =             if_tiocmget,
-       .tiocmset =             if_tiocmset,
-};
 
 static int if_open(struct tty_struct *tty, struct file *filp)
 {
@@ -355,7 +325,7 @@ done:
 static int if_write_room(struct tty_struct *tty)
 {
        struct cardstate *cs = tty->driver_data;
-       int retval = -ENODEV;
+       int retval;
 
        gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
@@ -498,6 +468,20 @@ out:
        mutex_unlock(&cs->mutex);
 }
 
+static const struct tty_operations if_ops = {
+       .open =                 if_open,
+       .close =                if_close,
+       .ioctl =                if_ioctl,
+       .write =                if_write,
+       .write_room =           if_write_room,
+       .chars_in_buffer =      if_chars_in_buffer,
+       .set_termios =          if_set_termios,
+       .throttle =             if_throttle,
+       .unthrottle =           if_unthrottle,
+       .tiocmget =             if_tiocmget,
+       .tiocmset =             if_tiocmset,
+};
+
 
 /* wakeup tasklet for the write operation */
 static void if_wake(unsigned long data)
index e3f0faca98d02e7a2002ad5d076274a6ee38b2b4..3a8c7532ee0d23ed1e896fe94ff017e9cbb82738 100644 (file)
    ethernet adaptor have the name "eth[0123...]".
    */
 
-extern struct net_device *ne2_probe(int unit);
 extern struct net_device *hp100_probe(int unit);
 extern struct net_device *ultra_probe(int unit);
-extern struct net_device *ultra32_probe(int unit);
 extern struct net_device *wd_probe(int unit);
-extern struct net_device *el2_probe(int unit);
 extern struct net_device *ne_probe(int unit);
-extern struct net_device *hp_probe(int unit);
-extern struct net_device *hp_plus_probe(int unit);
-extern struct net_device *express_probe(int unit);
-extern struct net_device *eepro_probe(int unit);
-extern struct net_device *at1700_probe(int unit);
 extern struct net_device *fmv18x_probe(int unit);
-extern struct net_device *eth16i_probe(int unit);
 extern struct net_device *i82596_probe(int unit);
-extern struct net_device *ewrk3_probe(int unit);
-extern struct net_device *el1_probe(int unit);
-extern struct net_device *el16_probe(int unit);
-extern struct net_device *elmc_probe(int unit);
-extern struct net_device *elplus_probe(int unit);
-extern struct net_device *ac3200_probe(int unit);
-extern struct net_device *es_probe(int unit);
-extern struct net_device *lne390_probe(int unit);
-extern struct net_device *e2100_probe(int unit);
-extern struct net_device *ni5010_probe(int unit);
-extern struct net_device *ni52_probe(int unit);
 extern struct net_device *ni65_probe(int unit);
 extern struct net_device *sonic_probe(int unit);
-extern struct net_device *seeq8005_probe(int unit);
 extern struct net_device *smc_init(int unit);
 extern struct net_device *atarilance_probe(int unit);
 extern struct net_device *sun3lance_probe(int unit);
@@ -77,13 +56,9 @@ extern struct net_device *tc515_probe(int unit);
 extern struct net_device *lance_probe(int unit);
 extern struct net_device *mac8390_probe(int unit);
 extern struct net_device *mac89x0_probe(int unit);
-extern struct net_device *mc32_probe(int unit);
 extern struct net_device *cops_probe(int unit);
 extern struct net_device *ltpc_probe(void);
 
-/* Detachable devices ("pocket adaptors") */
-extern struct net_device *de620_probe(int unit);
-
 /* Fibre Channel adapters */
 extern int iph5526_probe(struct net_device *dev);
 
@@ -110,29 +85,6 @@ static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe)
        return -ENODEV;
 }
 
-/*
- * This is a bit of an artificial separation as there are PCI drivers
- * that also probe for EISA cards (in the PCI group) and there are ISA
- * drivers that probe for EISA cards (in the ISA group).  These are the
- * legacy EISA only driver probes, and also the legacy PCI probes
- */
-
-static struct devprobe2 eisa_probes[] __initdata = {
-#ifdef CONFIG_ULTRA32
-       {ultra32_probe, 0},
-#endif
-#ifdef CONFIG_AC3200
-       {ac3200_probe, 0},
-#endif
-#ifdef CONFIG_ES3210
-       {es_probe, 0},
-#endif
-#ifdef CONFIG_LNE390
-       {lne390_probe, 0},
-#endif
-       {NULL, 0},
-};
-
 /*
  * ISA probes that touch addresses < 0x400 (including those that also
  * look for EISA/PCI cards in addition to ISA cards).
@@ -150,18 +102,6 @@ static struct devprobe2 isa_probes[] __initdata = {
 #ifdef CONFIG_WD80x3
        {wd_probe, 0},
 #endif
-#ifdef CONFIG_EL2              /* 3c503 */
-       {el2_probe, 0},
-#endif
-#ifdef CONFIG_HPLAN
-       {hp_probe, 0},
-#endif
-#ifdef CONFIG_HPLAN_PLUS
-       {hp_plus_probe, 0},
-#endif
-#ifdef CONFIG_E2100            /* Cabletron E21xx series. */
-       {e2100_probe, 0},
-#endif
 #if defined(CONFIG_NE2000) || \
     defined(CONFIG_NE_H8300)  /* ISA (use ne2k-pci for PCI cards) */
        {ne_probe, 0},
@@ -172,60 +112,20 @@ static struct devprobe2 isa_probes[] __initdata = {
 #ifdef CONFIG_SMC9194
        {smc_init, 0},
 #endif
-#ifdef CONFIG_SEEQ8005
-       {seeq8005_probe, 0},
-#endif
 #ifdef CONFIG_CS89x0
 #ifndef CONFIG_CS89x0_PLATFORM
        {cs89x0_probe, 0},
 #endif
 #endif
-#ifdef CONFIG_AT1700
-       {at1700_probe, 0},
-#endif
-#ifdef CONFIG_ETH16I
-       {eth16i_probe, 0},      /* ICL EtherTeam 16i/32 */
-#endif
-#ifdef CONFIG_EEXPRESS         /* Intel EtherExpress */
-       {express_probe, 0},
-#endif
-#ifdef CONFIG_EEXPRESS_PRO     /* Intel EtherExpress Pro/10 */
-       {eepro_probe, 0},
-#endif
-#ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
-       {ewrk3_probe, 0},
-#endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)     /* Intel I82596 */
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)        /* Intel I82596 */
        {i82596_probe, 0},
 #endif
-#ifdef CONFIG_EL1              /* 3c501 */
-       {el1_probe, 0},
-#endif
-#ifdef CONFIG_EL16             /* 3c507 */
-       {el16_probe, 0},
-#endif
-#ifdef CONFIG_ELPLUS           /* 3c505 */
-       {elplus_probe, 0},
-#endif
-#ifdef CONFIG_NI5010
-       {ni5010_probe, 0},
-#endif
-#ifdef CONFIG_NI52
-       {ni52_probe, 0},
-#endif
 #ifdef CONFIG_NI65
        {ni65_probe, 0},
 #endif
        {NULL, 0},
 };
 
-static struct devprobe2 parport_probes[] __initdata = {
-#ifdef CONFIG_DE620            /* D-Link DE-620 adapter */
-       {de620_probe, 0},
-#endif
-       {NULL, 0},
-};
-
 static struct devprobe2 m68k_probes[] __initdata = {
 #ifdef CONFIG_ATARILANCE       /* Lance-based Atari ethernet boards */
        {atarilance_probe, 0},
@@ -264,9 +164,7 @@ static void __init ethif_probe2(int unit)
                return;
 
        (void)( probe_list2(unit, m68k_probes, base_addr == 0) &&
-               probe_list2(unit, eisa_probes, base_addr == 0) &&
-               probe_list2(unit, isa_probes, base_addr == 0) &&
-               probe_list2(unit, parport_probes, base_addr == 0));
+               probe_list2(unit, isa_probes, base_addr == 0));
 }
 
 /*  Statically configured drivers -- order matters here. */
index a030e635f001169396092b53fb976f3adf34b2b0..84fabd69df4c0a9127ca64d7065dd4c41b396f41 100644 (file)
@@ -1127,7 +1127,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                                // INFO_RECEIVED_LOOPBACK_FRAMES
                                pr_err("%s: An illegal loopback occurred on adapter (%s).\n"
                                       "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
-                                      port->slave->dev->master->name, port->slave->dev->name);
+                                      port->slave->bond->dev->name, port->slave->dev->name);
                                return;
                        }
                        __update_selected(lacpdu, port);
@@ -1306,7 +1306,7 @@ static void ad_port_selection_logic(struct port *port)
                }
                if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
                        pr_warning("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
-                                  port->slave->dev->master->name,
+                                  port->slave->bond->dev->name,
                                   port->actor_port_number,
                                   port->slave->dev->name,
                                   port->aggregator->aggregator_identifier);
@@ -1386,7 +1386,7 @@ static void ad_port_selection_logic(struct port *port)
                                 port->aggregator->aggregator_identifier);
                } else {
                        pr_err("%s: Port %d (on %s) did not find a suitable aggregator\n",
-                              port->slave->dev->master->name,
+                              port->slave->bond->dev->name,
                               port->actor_port_number, port->slave->dev->name);
                }
        }
@@ -1463,7 +1463,7 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
 
        default:
                pr_warning("%s: Impossible agg select mode %d\n",
-                          curr->slave->dev->master->name,
+                          curr->slave->bond->dev->name,
                           __get_agg_selection_mode(curr->lag_ports));
                break;
        }
@@ -1571,7 +1571,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
                // check if any partner replys
                if (best->is_individual) {
                        pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
-                                  best->slave ? best->slave->dev->master->name : "NULL");
+                                  best->slave ? best->slave->bond->dev->name : "NULL");
                }
 
                best->is_active = 1;
@@ -1898,7 +1898,7 @@ int bond_3ad_bind_slave(struct slave *slave)
 
        if (bond == NULL) {
                pr_err("%s: The slave %s is not attached to its bond\n",
-                      slave->dev->master->name, slave->dev->name);
+                      slave->bond->dev->name, slave->dev->name);
                return -1;
        }
 
@@ -1973,7 +1973,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
                pr_warning("Warning: %s: Trying to unbind an uninitialized port on %s\n",
-                          slave->dev->master->name, slave->dev->name);
+                          slave->bond->dev->name, slave->dev->name);
                return;
        }
 
@@ -2009,7 +2009,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
 
                                if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
                                        pr_info("%s: Removing an active aggregator\n",
-                                               aggregator->slave->dev->master->name);
+                                               aggregator->slave->bond->dev->name);
                                        // select new active aggregator
                                         select_new_active_agg = 1;
                                }
@@ -2040,7 +2040,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
                                        ad_agg_selection_logic(__get_first_agg(port));
                        } else {
                                pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
-                                          slave->dev->master->name);
+                                          slave->bond->dev->name);
                        }
                } else { // in case that the only port related to this aggregator is the one we want to remove
                        select_new_active_agg = aggregator->is_active;
@@ -2048,7 +2048,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
                        ad_clear_agg(aggregator);
                        if (select_new_active_agg) {
                                pr_info("%s: Removing an active aggregator\n",
-                                       slave->dev->master->name);
+                                       slave->bond->dev->name);
                                // select new active aggregator
                                ad_agg_selection_logic(__get_first_agg(port));
                        }
@@ -2076,7 +2076,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
                                        ad_clear_agg(temp_aggregator);
                                        if (select_new_active_agg) {
                                                pr_info("%s: Removing an active aggregator\n",
-                                                       slave->dev->master->name);
+                                                       slave->bond->dev->name);
                                                // select new active aggregator
                                                ad_agg_selection_logic(__get_first_agg(port));
                                        }
@@ -2184,7 +2184,7 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u1
 
                if (!port->slave) {
                        pr_warning("%s: Warning: port of slave %s is uninitialized\n",
-                                  slave->dev->name, slave->dev->master->name);
+                                  slave->dev->name, slave->bond->dev->name);
                        return ret;
                }
 
@@ -2240,7 +2240,7 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
                pr_warning("Warning: %s: speed changed for uninitialized port on %s\n",
-                          slave->dev->master->name, slave->dev->name);
+                          slave->bond->dev->name, slave->dev->name);
                return;
        }
 
@@ -2268,7 +2268,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
                pr_warning("%s: Warning: duplex changed for uninitialized port on %s\n",
-                          slave->dev->master->name, slave->dev->name);
+                          slave->bond->dev->name, slave->dev->name);
                return;
        }
 
@@ -2297,7 +2297,7 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
                pr_warning("Warning: %s: link status changed for uninitialized port on %s\n",
-                          slave->dev->master->name, slave->dev->name);
+                          slave->bond->dev->name, slave->dev->name);
                return;
        }
 
index 7c9d136e74bef3f725264aeef91fae32d99da168..f5e05272302995cddb352ce4310524047d1a9dbe 100644 (file)
@@ -507,7 +507,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
                                 client_info->mac_dst);
                if (!skb) {
                        pr_err("%s: Error: failed to create an ARP packet\n",
-                              client_info->slave->dev->master->name);
+                              client_info->slave->bond->dev->name);
                        continue;
                }
 
@@ -517,7 +517,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
                        skb = vlan_put_tag(skb, client_info->vlan_id);
                        if (!skb) {
                                pr_err("%s: Error: failed to insert VLAN tag\n",
-                                      client_info->slave->dev->master->name);
+                                      client_info->slave->bond->dev->name);
                                continue;
                        }
                }
@@ -1043,7 +1043,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
        if (dev_set_mac_address(dev, &s_addr)) {
                pr_err("%s: Error: dev_set_mac_address of dev %s failed!\n"
                       "ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n",
-                      dev->master->name, dev->name);
+                      slave->bond->dev->name, dev->name);
                return -EOPNOTSUPP;
        }
        return 0;
index b7d45f367d4a6e604bdcd6c0a6aabb598587c3be..564cf4231f48a09246ae30a518983fcb6fa0a822 100644 (file)
@@ -746,11 +746,9 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
 {
        struct in_device *in_dev;
 
-       rcu_read_lock();
        in_dev = __in_dev_get_rcu(dev);
        if (in_dev)
                ip_mc_rejoin_groups(in_dev);
-       rcu_read_unlock();
 }
 
 /*
@@ -760,9 +758,10 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
  */
 static void bond_resend_igmp_join_requests(struct bonding *bond)
 {
-       struct net_device *bond_dev, *vlan_dev, *master_dev;
+       struct net_device *bond_dev, *vlan_dev, *upper_dev;
        struct vlan_entry *vlan;
 
+       rcu_read_lock();
        read_lock(&bond->lock);
 
        bond_dev = bond->dev;
@@ -774,18 +773,14 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
         * if bond is enslaved to a bridge,
         * then rejoin all groups on its master
         */
-       master_dev = bond_dev->master;
-       if (master_dev)
-               if ((master_dev->priv_flags & IFF_EBRIDGE)
-                       && (bond_dev->priv_flags & IFF_BRIDGE_PORT))
-                       __bond_resend_igmp_join_requests(master_dev);
+       upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
+       if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
+               __bond_resend_igmp_join_requests(upper_dev);
 
        /* rejoin all groups on vlan devices */
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               rcu_read_lock();
                vlan_dev = __vlan_find_dev_deep(bond_dev,
                                                vlan->vlan_id);
-               rcu_read_unlock();
                if (vlan_dev)
                        __bond_resend_igmp_join_requests(vlan_dev);
        }
@@ -794,13 +789,16 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
                queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
 
        read_unlock(&bond->lock);
+       rcu_read_unlock();
 }
 
 static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            mcast_work.work);
+       rcu_read_lock();
        bond_resend_igmp_join_requests(bond);
+       rcu_read_unlock();
 }
 
 /*
@@ -1493,6 +1491,27 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
        return ret;
 }
 
+static int bond_master_upper_dev_link(struct net_device *bond_dev,
+                                     struct net_device *slave_dev)
+{
+       int err;
+
+       err = netdev_master_upper_dev_link(slave_dev, bond_dev);
+       if (err)
+               return err;
+       slave_dev->flags |= IFF_SLAVE;
+       rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
+       return 0;
+}
+
+static void bond_upper_dev_unlink(struct net_device *bond_dev,
+                                 struct net_device *slave_dev)
+{
+       netdev_upper_dev_unlink(slave_dev, bond_dev);
+       slave_dev->flags &= ~IFF_SLAVE;
+       rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
+}
+
 /* enslave device <slave> to bond device <master> */
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 {
@@ -1655,9 +1674,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                }
        }
 
-       res = netdev_set_bond_master(slave_dev, bond_dev);
+       res = bond_master_upper_dev_link(bond_dev, slave_dev);
        if (res) {
-               pr_debug("Error %d calling netdev_set_bond_master\n", res);
+               pr_debug("Error %d calling bond_master_upper_dev_link\n", res);
                goto err_restore_mac;
        }
 
@@ -1891,7 +1910,7 @@ err_close:
        dev_close(slave_dev);
 
 err_unset_master:
-       netdev_set_bond_master(slave_dev, NULL);
+       bond_upper_dev_unlink(bond_dev, slave_dev);
 
 err_restore_mac:
        if (!bond->params.fail_over_mac) {
@@ -1936,7 +1955,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* slave is not a slave or master is not master of this slave */
        if (!(slave_dev->flags & IFF_SLAVE) ||
-           (slave_dev->master != bond_dev)) {
+           !netdev_has_upper_dev(slave_dev, bond_dev)) {
                pr_err("%s: Error: cannot release %s.\n",
                       bond_dev->name, slave_dev->name);
                return -EINVAL;
@@ -2080,7 +2099,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
                netif_addr_unlock_bh(bond_dev);
        }
 
-       netdev_set_bond_master(slave_dev, NULL);
+       bond_upper_dev_unlink(bond_dev, slave_dev);
 
        slave_disable_netpoll(slave);
 
@@ -2195,7 +2214,7 @@ static int bond_release_all(struct net_device *bond_dev)
                        netif_addr_unlock_bh(bond_dev);
                }
 
-               netdev_set_bond_master(slave_dev, NULL);
+               bond_upper_dev_unlink(bond_dev, slave_dev);
 
                slave_disable_netpoll(slave);
 
@@ -2259,8 +2278,9 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
        if (!USES_PRIMARY(bond->params.mode))
                return -EINVAL;
 
-       /* Verify that master_dev is indeed the master of slave_dev */
-       if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev))
+       /* Verify that bond_dev is indeed the master of slave_dev */
+       if (!(slave_dev->flags & IFF_SLAVE) ||
+           !netdev_has_upper_dev(slave_dev, bond_dev))
                return -EINVAL;
 
        read_lock(&bond->lock);
@@ -3258,36 +3278,32 @@ static int bond_master_netdev_event(unsigned long event,
 static int bond_slave_netdev_event(unsigned long event,
                                   struct net_device *slave_dev)
 {
-       struct net_device *bond_dev = slave_dev->master;
-       struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave = NULL;
+       struct slave *slave = bond_slave_get_rtnl(slave_dev);
+       struct bonding *bond = slave->bond;
+       struct net_device *bond_dev = slave->bond->dev;
+       u32 old_speed;
+       u8 old_duplex;
 
        switch (event) {
        case NETDEV_UNREGISTER:
-               if (bond_dev) {
-                       if (bond->setup_by_slave)
-                               bond_release_and_destroy(bond_dev, slave_dev);
-                       else
-                               bond_release(bond_dev, slave_dev);
-               }
+               if (bond->setup_by_slave)
+                       bond_release_and_destroy(bond_dev, slave_dev);
+               else
+                       bond_release(bond_dev, slave_dev);
                break;
        case NETDEV_UP:
        case NETDEV_CHANGE:
-               slave = bond_get_slave_by_dev(bond, slave_dev);
-               if (slave) {
-                       u32 old_speed = slave->speed;
-                       u8  old_duplex = slave->duplex;
+               old_speed = slave->speed;
+               old_duplex = slave->duplex;
 
-                       bond_update_speed_duplex(slave);
+               bond_update_speed_duplex(slave);
 
-                       if (bond->params.mode == BOND_MODE_8023AD) {
-                               if (old_speed != slave->speed)
-                                       bond_3ad_adapter_speed_changed(slave);
-                               if (old_duplex != slave->duplex)
-                                       bond_3ad_adapter_duplex_changed(slave);
-                       }
+               if (bond->params.mode == BOND_MODE_8023AD) {
+                       if (old_speed != slave->speed)
+                               bond_3ad_adapter_speed_changed(slave);
+                       if (old_duplex != slave->duplex)
+                               bond_3ad_adapter_duplex_changed(slave);
                }
-
                break;
        case NETDEV_DOWN:
                /*
@@ -4314,11 +4330,12 @@ void bond_set_mode_ops(struct bonding *bond, int mode)
 }
 
 static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
-                                   struct ethtool_drvinfo *drvinfo)
+                                    struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver, DRV_NAME, 32);
-       strncpy(drvinfo->version, DRV_VERSION, 32);
-       snprintf(drvinfo->fw_version, 32, "%d", BOND_ABI_VERSION);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d",
+                BOND_ABI_VERSION);
 }
 
 static const struct ethtool_ops bond_ethtool_ops = {
index 21b68e5c14fd24c49d606289220f51a2a9902e65..0d282d20b5a81797a728df552a36f122fe53730a 100644 (file)
@@ -258,6 +258,9 @@ static inline bool bond_vlan_used(struct bonding *bond)
 #define bond_slave_get_rcu(dev) \
        ((struct slave *) rcu_dereference(dev->rx_handler_data))
 
+#define bond_slave_get_rtnl(dev) \
+       ((struct slave *) rtnl_dereference(dev->rx_handler_data))
+
 /**
  * Returns NULL if the net_device does not belong to any of the bond's slaves
  *
@@ -280,11 +283,9 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
 
 static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
 {
-       if (!slave || !slave->dev->master) {
+       if (!slave || !slave->bond)
                return NULL;
-       }
-
-       return netdev_priv(slave->dev->master);
+       return slave->bond;
 }
 
 static inline bool bond_is_lb(const struct bonding *bond)
@@ -360,10 +361,9 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
 
 static inline void bond_set_slave_inactive_flags(struct slave *slave)
 {
-       struct bonding *bond = netdev_priv(slave->dev->master);
-       if (!bond_is_lb(bond))
+       if (!bond_is_lb(slave->bond))
                bond_set_backup_slave(slave);
-       if (!bond->params.all_slaves_active)
+       if (!slave->bond->params.all_slaves_active)
                slave->inactive = 1;
 }
 
index b56bd9e80957f0dc5f8dde896cb648e7cf939ab5..1cca19f1c490b5807f5862d6d75d90f7752b6c9e 100644 (file)
@@ -1,9 +1,7 @@
 menu "CAN Device Drivers"
-       depends on CAN
 
 config CAN_VCAN
        tristate "Virtual Local CAN Interface (vcan)"
-       depends on CAN
        ---help---
          Similar to the network loopback devices, vcan offers a
          virtual local CAN interface.
@@ -13,7 +11,6 @@ config CAN_VCAN
 
 config CAN_SLCAN
        tristate "Serial / USB serial CAN Adaptors (slcan)"
-       depends on CAN
        ---help---
          CAN driver for several 'low cost' CAN interfaces that are attached
          via serial lines or via USB-to-serial adapters using the LAWICEL
@@ -33,16 +30,16 @@ config CAN_SLCAN
 
 config CAN_DEV
        tristate "Platform CAN drivers with Netlink support"
-       depends on CAN
        default y
        ---help---
          Enables the common framework for platform CAN drivers with Netlink
          support. This is the standard library for CAN drivers.
          If unsure, say Y.
 
+if CAN_DEV
+
 config CAN_CALC_BITTIMING
        bool "CAN bit-timing calculation"
-       depends on CAN_DEV
        default y
        ---help---
          If enabled, CAN bit-timing parameters will be calculated for the
@@ -54,15 +51,26 @@ config CAN_CALC_BITTIMING
          arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
          If unsure, say Y.
 
+config CAN_LEDS
+       bool "Enable LED triggers for Netlink based drivers"
+       depends on LEDS_CLASS
+       select LEDS_TRIGGERS
+       ---help---
+         This option adds two LED triggers for packet receive and transmit
+         events on each supported CAN device.
+
+         Say Y here if you are working on a system with led-class supported
+         LEDs and you want to use them as canbus activity indicators.
+
 config CAN_AT91
        tristate "Atmel AT91 onchip CAN controller"
-       depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
+       depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
        ---help---
          This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
          and AT91SAM9X5 processors.
 
 config CAN_TI_HECC
-       depends on CAN_DEV && ARCH_OMAP3
+       depends on ARCH_OMAP3
        tristate "TI High End CAN Controller"
        ---help---
          Driver for TI HECC (High End CAN Controller) module found on many
@@ -70,12 +78,12 @@ config CAN_TI_HECC
 
 config CAN_MCP251X
        tristate "Microchip MCP251x SPI CAN controllers"
-       depends on CAN_DEV && SPI && HAS_DMA
+       depends on SPI && HAS_DMA
        ---help---
          Driver for the Microchip MCP251x SPI CAN controllers.
 
 config CAN_BFIN
-       depends on CAN_DEV && (BF534 || BF536 || BF537 || BF538 || BF539 || BF54x)
+       depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
        tristate "Analog Devices Blackfin on-chip CAN"
        ---help---
          Driver for the Analog Devices Blackfin on-chip CAN controllers
@@ -85,7 +93,7 @@ config CAN_BFIN
 
 config CAN_JANZ_ICAN3
        tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
-       depends on CAN_DEV && MFD_JANZ_CMODIO
+       depends on MFD_JANZ_CMODIO
        ---help---
          Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
          connects to a MODULbus carrier board.
@@ -98,13 +106,13 @@ config HAVE_CAN_FLEXCAN
 
 config CAN_FLEXCAN
        tristate "Support for Freescale FLEXCAN based chips"
-       depends on CAN_DEV && HAVE_CAN_FLEXCAN
+       depends on HAVE_CAN_FLEXCAN
        ---help---
          Say Y here if you want to support for Freescale FlexCAN.
 
 config PCH_CAN
        tristate "Intel EG20T PCH CAN controller"
-       depends on CAN_DEV && PCI
+       depends on PCI
        ---help---
          This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
          is an IOH for x86 embedded processor (Intel Atom E6xx series).
@@ -112,7 +120,7 @@ config PCH_CAN
 
 config CAN_GRCAN
        tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
-       depends on CAN_DEV && OF
+       depends on OF
        ---help---
          Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
          Note that the driver supports little endian, even though little
@@ -131,9 +139,10 @@ source "drivers/net/can/usb/Kconfig"
 
 source "drivers/net/can/softing/Kconfig"
 
+endif
+
 config CAN_DEBUG_DEVICES
        bool "CAN devices debugging messages"
-       depends on CAN
        ---help---
          Say Y here if you want the CAN device drivers to produce a bunch of
          debug messages to the system log.  Select this if you are having
index 7de59862bbe940aeddc9ac93a3c1bd16d8eac30a..c7440392adbbaaabd5ca5b8ba872ba18c23f41d2 100644 (file)
@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN)         += slcan.o
 obj-$(CONFIG_CAN_DEV)          += can-dev.o
 can-dev-y                      := dev.o
 
+can-dev-$(CONFIG_CAN_LEDS)     += led.o
+
 obj-y                          += usb/
 obj-y                          += softing/
 
index 81baefda037bfe1d9d6ceb1058162dfe0ce09d0d..44f363792b59d5b04b7f47585ca8db0bbb4fc1bb 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 
 #define AT91_MB_MASK(i)                ((1 << (i)) - 1)
 
@@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+
+       can_led_event(dev, CAN_LED_EVENT_RX);
 }
 
 /**
@@ -875,6 +878,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
                        /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
                        can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
                        dev->stats.tx_packets++;
+                       can_led_event(dev, CAN_LED_EVENT_TX);
                }
        }
 
@@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev)
                goto out_close;
        }
 
+       can_led_event(dev, CAN_LED_EVENT_OPEN);
+
        /* start chip and queuing */
        at91_chip_start(dev);
        napi_enable(&priv->napi);
@@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev)
 
        close_candev(dev);
 
+       can_led_event(dev, CAN_LED_EVENT_STOP);
+
        return 0;
 }
 
@@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev)
                goto exit_free;
        }
 
+       devm_can_led_init(dev);
+
        dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
                 priv->reg_base, dev->irq);
 
index 3b83bafcd9474c5089e4f1f17a05944471066dcd..61ffc12d8fd8e4e01056b06fd3ae73be7abe513e 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig CAN_C_CAN
        tristate "Bosch C_CAN/D_CAN devices"
-       depends on CAN_DEV && HAS_IOMEM
+       depends on HAS_IOMEM
 
 if CAN_C_CAN
 
index 58607f196c9ee5e5c3d214c70ca9abe0e2a5b6d0..285f763e3cd13ca8dbdc2329283e850ebe6cdae5 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 
 #include "c_can.h"
 
@@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
        stats->rx_packets++;
        stats->rx_bytes += frame->can_dlc;
 
+       can_led_event(dev, CAN_LED_EVENT_RX);
+
        return 0;
 }
 
@@ -751,6 +754,7 @@ static void c_can_do_tx(struct net_device *dev)
                                        C_CAN_IFACE(MSGCTRL_REG, 0))
                                        & IF_MCONT_DLC_MASK;
                        stats->tx_packets++;
+                       can_led_event(dev, CAN_LED_EVENT_TX);
                        c_can_inval_msg_object(dev, 0, msg_obj_no);
                } else {
                        break;
@@ -1115,6 +1119,8 @@ static int c_can_open(struct net_device *dev)
 
        napi_enable(&priv->napi);
 
+       can_led_event(dev, CAN_LED_EVENT_OPEN);
+
        /* start the c_can controller */
        c_can_start(dev);
 
@@ -1143,6 +1149,8 @@ static int c_can_close(struct net_device *dev)
        c_can_reset_ram(priv, false);
        c_can_pm_runtime_put_sync(priv);
 
+       can_led_event(dev, CAN_LED_EVENT_STOP);
+
        return 0;
 }
 
@@ -1268,6 +1276,8 @@ int register_c_can_dev(struct net_device *dev)
        err = register_candev(dev);
        if (err)
                c_can_pm_runtime_disable(priv);
+       else
+               devm_can_led_init(dev);
 
        return err;
 }
index 22c07a8c8b43735b742d4ff9bf1be35367c8a726..6a9a5ba792207a3ede96ca162606f558e15cc8f8 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig CAN_CC770
        tristate "Bosch CC770 and Intel AN82527 devices"
-       depends on CAN_DEV && HAS_IOMEM
+       depends on HAS_IOMEM
 
 if CAN_CC770
 
index 8233e5ed2939dcfe415ee119edf8c3aaf042c47d..f9cba4123c663084b66c2dbdaac5885a579278fd 100644 (file)
@@ -24,7 +24,9 @@
 #include <linux/if_arp.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
+#include <linux/can/skb.h>
 #include <linux/can/netlink.h>
+#include <linux/can/led.h>
 #include <net/rtnetlink.h>
 
 #define MOD_DESC "CAN device driver interface"
@@ -501,13 +503,18 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
 {
        struct sk_buff *skb;
 
-       skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
+       skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+                              sizeof(struct can_frame));
        if (unlikely(!skb))
                return NULL;
 
        skb->protocol = htons(ETH_P_CAN);
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       can_skb_reserve(skb);
+       can_skb_prv(skb)->ifindex = dev->ifindex;
+
        *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
        memset(*cf, 0, sizeof(struct can_frame));
 
@@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(unregister_candev);
 
+/*
+ * Test if a network device is a candev based device
+ * and return the can_priv* if so.
+ */
+struct can_priv *safe_candev_priv(struct net_device *dev)
+{
+       if ((dev->type != ARPHRD_CAN) || (dev->rtnl_link_ops != &can_link_ops))
+               return NULL;
+
+       return netdev_priv(dev);
+}
+EXPORT_SYMBOL_GPL(safe_candev_priv);
+
 static __init int can_dev_init(void)
 {
        int err;
 
+       can_led_notifier_init();
+
        err = rtnl_link_register(&can_link_ops);
        if (!err)
                printk(KERN_INFO MOD_DESC "\n");
@@ -809,6 +831,8 @@ module_init(can_dev_init);
 static __exit void can_dev_exit(void)
 {
        rtnl_link_unregister(&can_link_ops);
+
+       can_led_notifier_exit();
 }
 module_exit(can_dev_exit);
 
index 0289a6d86f660d5e97f9a2f34a2d37c6d7f1d53d..769d29ed106dbb1336745510b7fa2ff60f387bf7 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 #include <linux/can/platform/flexcan.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev)
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
 
+       can_led_event(dev, CAN_LED_EVENT_RX);
+
        return 1;
 }
 
@@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
        if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
                stats->tx_bytes += can_get_echo_skb(dev, 0);
                stats->tx_packets++;
+               can_led_event(dev, CAN_LED_EVENT_TX);
                flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
                netif_wake_queue(dev);
        }
@@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev)
        err = flexcan_chip_start(dev);
        if (err)
                goto out_close;
+
+       can_led_event(dev, CAN_LED_EVENT_OPEN);
+
        napi_enable(&priv->napi);
        netif_start_queue(dev);
 
@@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev)
 
        close_candev(dev);
 
+       can_led_event(dev, CAN_LED_EVENT_STOP);
+
        return 0;
 }
 
@@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev)
                goto failed_register;
        }
 
+       devm_can_led_init(dev);
+
        dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
                 priv->base, dev->irq);
 
diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c
new file mode 100644 (file)
index 0000000..f27fca6
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
+ * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/can/dev.h>
+
+#include <linux/can/led.h>
+
+static unsigned long led_delay = 50;
+module_param(led_delay, ulong, 0644);
+MODULE_PARM_DESC(led_delay,
+               "blink delay time for activity leds (msecs, default: 50).");
+
+/* Trigger a LED event in response to a CAN device event */
+void can_led_event(struct net_device *netdev, enum can_led_event event)
+{
+       struct can_priv *priv = netdev_priv(netdev);
+
+       switch (event) {
+       case CAN_LED_EVENT_OPEN:
+               led_trigger_event(priv->tx_led_trig, LED_FULL);
+               led_trigger_event(priv->rx_led_trig, LED_FULL);
+               break;
+       case CAN_LED_EVENT_STOP:
+               led_trigger_event(priv->tx_led_trig, LED_OFF);
+               led_trigger_event(priv->rx_led_trig, LED_OFF);
+               break;
+       case CAN_LED_EVENT_TX:
+               if (led_delay)
+                       led_trigger_blink_oneshot(priv->tx_led_trig,
+                                                 &led_delay, &led_delay, 1);
+               break;
+       case CAN_LED_EVENT_RX:
+               if (led_delay)
+                       led_trigger_blink_oneshot(priv->rx_led_trig,
+                                                 &led_delay, &led_delay, 1);
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(can_led_event);
+
+static void can_led_release(struct device *gendev, void *res)
+{
+       struct can_priv *priv = netdev_priv(to_net_dev(gendev));
+
+       led_trigger_unregister_simple(priv->tx_led_trig);
+       led_trigger_unregister_simple(priv->rx_led_trig);
+}
+
+/* Register CAN LED triggers for a CAN device
+ *
+ * This is normally called from a driver's probe function
+ */
+void devm_can_led_init(struct net_device *netdev)
+{
+       struct can_priv *priv = netdev_priv(netdev);
+       void *res;
+
+       res = devres_alloc(can_led_release, 0, GFP_KERNEL);
+       if (!res) {
+               netdev_err(netdev, "cannot register LED triggers\n");
+               return;
+       }
+
+       snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
+                "%s-tx", netdev->name);
+       snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
+                "%s-rx", netdev->name);
+
+       led_trigger_register_simple(priv->tx_led_trig_name,
+                                   &priv->tx_led_trig);
+       led_trigger_register_simple(priv->rx_led_trig_name,
+                                   &priv->rx_led_trig);
+
+       devres_add(&netdev->dev, res);
+}
+EXPORT_SYMBOL_GPL(devm_can_led_init);
+
+/* NETDEV rename notifier to rename the associated led triggers too */
+static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
+                       void *data)
+{
+       struct net_device *netdev = data;
+       struct can_priv *priv = safe_candev_priv(netdev);
+       char name[CAN_LED_NAME_SZ];
+
+       if (!priv)
+               return NOTIFY_DONE;
+
+       if (msg == NETDEV_CHANGENAME) {
+               snprintf(name, sizeof(name), "%s-tx", netdev->name);
+               led_trigger_rename_static(name, priv->tx_led_trig);
+
+               snprintf(name, sizeof(name), "%s-rx", netdev->name);
+               led_trigger_rename_static(name, priv->rx_led_trig);
+       }
+
+       return NOTIFY_DONE;
+}
+
+/* notifier block for netdevice event */
+static struct notifier_block can_netdev_notifier __read_mostly = {
+       .notifier_call = can_led_notifier,
+};
+
+int __init can_led_notifier_init(void)
+{
+       return register_netdevice_notifier(&can_netdev_notifier);
+}
+
+void __exit can_led_notifier_exit(void)
+{
+       unregister_netdevice_notifier(&can_netdev_notifier);
+}
index 5eaf47b8e37bc4427a7004b1199da5dee8d7bccc..f32b9fc6a983205151feabc8512e1fac5a7df88a 100644 (file)
@@ -60,6 +60,7 @@
 
 #include <linux/can/core.h>
 #include <linux/can/dev.h>
+#include <linux/can/led.h>
 #include <linux/can/platform/mcp251x.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
@@ -494,6 +495,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
 
        priv->net->stats.rx_packets++;
        priv->net->stats.rx_bytes += frame->can_dlc;
+
+       can_led_event(priv->net, CAN_LED_EVENT_RX);
+
        netif_rx_ni(skb);
 }
 
@@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net)
 
        mutex_unlock(&priv->mcp_lock);
 
+       can_led_event(net, CAN_LED_EVENT_STOP);
+
        return 0;
 }
 
@@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
                if (intf & CANINTF_TX) {
                        net->stats.tx_packets++;
                        net->stats.tx_bytes += priv->tx_len - 1;
+                       can_led_event(net, CAN_LED_EVENT_TX);
                        if (priv->tx_len) {
                                can_get_echo_skb(net, 0);
                                priv->tx_len = 0;
@@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net)
                mcp251x_open_clean(net);
                goto open_unlock;
        }
+
+       can_led_event(net, CAN_LED_EVENT_OPEN);
+
        netif_wake_queue(net);
 
 open_unlock:
@@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi)
                pdata->transceiver_enable(0);
 
        ret = register_candev(net);
-       if (!ret) {
-               dev_info(&spi->dev, "probed\n");
-               return ret;
-       }
+       if (ret)
+               goto error_probe;
+
+       devm_can_led_init(net);
+
+       dev_info(&spi->dev, "probed\n");
+
+       return ret;
+
 error_probe:
        if (!mcp251x_enable_dma)
                kfree(priv->spi_rx_buf);
index d38706958af6c7e3dad46ca3358685c7d2c7ebf8..f19be5269e7be55ae92ccdb12f2274768aeb5ddf 100644 (file)
@@ -1,5 +1,5 @@
 config CAN_MSCAN
-       depends on CAN_DEV && (PPC || M68K)
+       depends on PPC || M68K
        tristate "Support for Freescale MSCAN based chips"
        ---help---
          The Motorola Scalable Controller Area Network (MSCAN) definition
index 92f73c708a3d7c3ec80133fb4b2f05872fd11849..b39ca5b3ea7faee34c2264ea7fbc6ac14e3caf35 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig CAN_SJA1000
        tristate "Philips/NXP SJA1000 devices"
-       depends on CAN_DEV && HAS_IOMEM
+       depends on HAS_IOMEM
 
 if CAN_SJA1000
 
@@ -99,11 +99,11 @@ config CAN_TSCAN1
        tristate "TS-CAN1 PC104 boards"
        depends on ISA
        help
-       This driver is for Technologic Systems' TSCAN-1 PC104 boards.
-       http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
-       The driver supports multiple boards and automatically configures them:
-       PLD IO base addresses are read from jumpers JP1 and JP2,
-       IRQ numbers are read from jumpers JP4 and JP5,
-       SJA1000 IO base addresses are chosen heuristically (first that works).
+         This driver is for Technologic Systems' TSCAN-1 PC104 boards.
+         http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
+         The driver supports multiple boards and automatically configures them:
+         PLD IO base addresses are read from jumpers JP1 and JP2,
+         IRQ numbers are read from jumpers JP4 and JP5,
+         SJA1000 IO base addresses are chosen heuristically (first that works).
 
 endif
index 83ee11eca0e2de4a54220bbc9e2b0d55c6edf057..daf4013a8fc720ca0c73a9df96b647ad5c314839 100644 (file)
@@ -60,6 +60,7 @@
 
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 
 #include "sja1000.h"
 
@@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+
+       can_led_event(dev, CAN_LED_EVENT_RX);
 }
 
 static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
@@ -521,6 +524,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
                                can_get_echo_skb(dev, 0);
                        }
                        netif_wake_queue(dev);
+                       can_led_event(dev, CAN_LED_EVENT_TX);
                }
                if (isrc & IRQ_RI) {
                        /* receive interrupt */
@@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev)
        /* init and start chi */
        sja1000_start(dev);
 
+       can_led_event(dev, CAN_LED_EVENT_OPEN);
+
        netif_start_queue(dev);
 
        return 0;
@@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev)
 
        close_candev(dev);
 
+       can_led_event(dev, CAN_LED_EVENT_STOP);
+
        return 0;
 }
 
@@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = {
 
 int register_sja1000dev(struct net_device *dev)
 {
+       int ret;
+
        if (!sja1000_probe_chip(dev))
                return -ENODEV;
 
@@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev)
        set_reset_mode(dev);
        chipset_init(dev);
 
-       return register_candev(dev);
+       ret =  register_candev(dev);
+
+       if (!ret)
+               devm_can_led_init(dev);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(register_sja1000dev);
 
index adc3708d882929d2caab589caec48e519bf7af24..06b7e097d36e5ed3117e9d1dc8258ee74d51c6be 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/can.h>
+#include <linux/can/skb.h>
 
 static __initconst const char banner[] =
        KERN_INFO "slcan: serial line CAN interface driver\n";
@@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl)
                cf.data[i] |= tmp;
        }
 
-       skb = dev_alloc_skb(sizeof(struct can_frame));
+       skb = dev_alloc_skb(sizeof(struct can_frame) +
+                           sizeof(struct can_skb_priv));
        if (!skb)
                return;
 
@@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl)
        skb->protocol = htons(ETH_P_CAN);
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       can_skb_reserve(skb);
+       can_skb_prv(skb)->ifindex = sl->dev->ifindex;
+
        memcpy(skb_put(skb, sizeof(struct can_frame)),
               &cf, sizeof(struct can_frame));
        netif_rx_ni(skb);
index 5de46a9a77bb58d468d6ddaa5181a5e604a3b4f9..96b6fe158b5bceeb90cdf4540f31f9f0dd68015f 100644 (file)
@@ -1,6 +1,6 @@
 config CAN_SOFTING
        tristate "Softing Gmbh CAN generic support"
-       depends on CAN_DEV && HAS_IOMEM
+       depends on HAS_IOMEM
        ---help---
          Support for CAN cards from Softing Gmbh & some cards
          from Vector Gmbh.
index 300581b24ff32860447e3646079024646e77a592..f21fc37ec578d3926a09cda2706e2be610e593d8 100644 (file)
@@ -50,6 +50,7 @@
 
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 #include <linux/can/platform/ti_hecc.h>
 
 #define DRV_NAME "ti_hecc"
@@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
        spin_unlock_irqrestore(&priv->mbx_lock, flags);
 
        stats->rx_bytes += cf->can_dlc;
+       can_led_event(priv->ndev, CAN_LED_EVENT_RX);
        netif_receive_skb(skb);
        stats->rx_packets++;
 
@@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
                        stats->tx_bytes += hecc_read_mbx(priv, mbxno,
                                                HECC_CANMCF) & 0xF;
                        stats->tx_packets++;
+                       can_led_event(ndev, CAN_LED_EVENT_TX);
                        can_get_echo_skb(ndev, mbxno);
                        --priv->tx_tail;
                }
@@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev)
                return err;
        }
 
+       can_led_event(ndev, CAN_LED_EVENT_OPEN);
+
        ti_hecc_start(ndev);
        napi_enable(&priv->napi);
        netif_start_queue(ndev);
@@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev)
        close_candev(ndev);
        ti_hecc_transceiver_switch(priv, 0);
 
+       can_led_event(ndev, CAN_LED_EVENT_STOP);
+
        return 0;
 }
 
@@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "register_candev() failed\n");
                goto probe_exit_clk;
        }
+
+       devm_can_led_init(ndev);
+
        dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
                priv->base, (u32) ndev->irq);
 
index a4e4bee35710fa3f71b1b597c98782765603c45f..fc96a3d83ebecde338cdc5fd1d7b12f5ee9fbc25 100644 (file)
@@ -1,5 +1,5 @@
 menu "CAN USB interfaces"
-       depends on USB && CAN_DEV
+       depends on USB
 
 config CAN_EMS_USB
        tristate "EMS CPC-USB/ARM7 CAN/USB interface"
@@ -48,4 +48,10 @@ config CAN_PEAK_USB
          This driver supports the PCAN-USB and PCAN-USB Pro adapters
          from PEAK-System Technik (http://www.peak-system.com).
 
+config CAN_8DEV_USB
+       tristate "8 devices USB2CAN interface"
+       ---help---
+         This driver supports the USB2CAN interface
+         from 8 devices (http://www.8devices.com).
+
 endmenu
index 80a2ee41fd61726dc43b70724d20e6c63c9b8cac..becef460a91aeb28851e91752b67ddec84ef931c 100644 (file)
@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
 obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
 obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
+obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
new file mode 100644 (file)
index 0000000..f789e6f
--- /dev/null
@@ -0,0 +1,1033 @@
+/*
+ * CAN driver for "8 devices" USB2CAN converter
+ *
+ * Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.
+ *
+ * This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c
+ * and drivers/net/can/usb/esd_usb2.c
+ *
+ * Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de)
+ * for testing and fixing this driver. Also many thanks to "8 devices",
+ * who were very cooperative and answered my questions.
+ */
+
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/led.h>
+
+/* driver constants */
+#define MAX_RX_URBS                    20
+#define MAX_TX_URBS                    20
+#define RX_BUFFER_SIZE                 64
+
+/* vendor and product id */
+#define USB_8DEV_VENDOR_ID             0x0483
+#define USB_8DEV_PRODUCT_ID            0x1234
+
+/* endpoints */
+enum usb_8dev_endpoint {
+       USB_8DEV_ENDP_DATA_RX = 1,
+       USB_8DEV_ENDP_DATA_TX,
+       USB_8DEV_ENDP_CMD_RX,
+       USB_8DEV_ENDP_CMD_TX
+};
+
+/* device CAN clock */
+#define USB_8DEV_ABP_CLOCK             32000000
+
+/* setup flags */
+#define USB_8DEV_SILENT                        0x01
+#define USB_8DEV_LOOPBACK              0x02
+#define USB_8DEV_DISABLE_AUTO_RESTRANS 0x04
+#define USB_8DEV_STATUS_FRAME          0x08
+
+/* commands */
+enum usb_8dev_cmd {
+       USB_8DEV_RESET = 1,
+       USB_8DEV_OPEN,
+       USB_8DEV_CLOSE,
+       USB_8DEV_SET_SPEED,
+       USB_8DEV_SET_MASK_FILTER,
+       USB_8DEV_GET_STATUS,
+       USB_8DEV_GET_STATISTICS,
+       USB_8DEV_GET_SERIAL,
+       USB_8DEV_GET_SOFTW_VER,
+       USB_8DEV_GET_HARDW_VER,
+       USB_8DEV_RESET_TIMESTAMP,
+       USB_8DEV_GET_SOFTW_HARDW_VER
+};
+
+/* command options */
+#define USB_8DEV_BAUD_MANUAL           0x09
+#define USB_8DEV_CMD_START             0x11
+#define USB_8DEV_CMD_END               0x22
+
+#define USB_8DEV_CMD_SUCCESS           0
+#define USB_8DEV_CMD_ERROR             255
+
+#define USB_8DEV_CMD_TIMEOUT           1000
+
+/* frames */
+#define USB_8DEV_DATA_START            0x55
+#define USB_8DEV_DATA_END              0xAA
+
+#define USB_8DEV_TYPE_CAN_FRAME                0
+#define USB_8DEV_TYPE_ERROR_FRAME      3
+
+#define USB_8DEV_EXTID                 0x01
+#define USB_8DEV_RTR                   0x02
+#define USB_8DEV_ERR_FLAG              0x04
+
+/* status */
+#define USB_8DEV_STATUSMSG_OK          0x00  /* Normal condition. */
+#define USB_8DEV_STATUSMSG_OVERRUN     0x01  /* Overrun occured when sending */
+#define USB_8DEV_STATUSMSG_BUSLIGHT    0x02  /* Error counter has reached 96 */
+#define USB_8DEV_STATUSMSG_BUSHEAVY    0x03  /* Error count. has reached 128 */
+#define USB_8DEV_STATUSMSG_BUSOFF      0x04  /* Device is in BUSOFF */
+#define USB_8DEV_STATUSMSG_STUFF       0x20  /* Stuff Error */
+#define USB_8DEV_STATUSMSG_FORM                0x21  /* Form Error */
+#define USB_8DEV_STATUSMSG_ACK         0x23  /* Ack Error */
+#define USB_8DEV_STATUSMSG_BIT0                0x24  /* Bit1 Error */
+#define USB_8DEV_STATUSMSG_BIT1                0x25  /* Bit0 Error */
+#define USB_8DEV_STATUSMSG_CRC         0x27  /* CRC Error */
+
+#define USB_8DEV_RP_MASK               0x7F  /* Mask for Receive Error Bit */
+
+
+/* table of devices that work with this driver */
+static const struct usb_device_id usb_8dev_table[] = {
+       { USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) },
+       { }                                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_8dev_table);
+
+struct usb_8dev_tx_urb_context {
+       struct usb_8dev_priv *priv;
+
+       u32 echo_index;
+       u8 dlc;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_8dev_priv {
+       struct can_priv can; /* must be the first member */
+
+       struct sk_buff *echo_skb[MAX_TX_URBS];
+
+       struct usb_device *udev;
+       struct net_device *netdev;
+
+       atomic_t active_tx_urbs;
+       struct usb_anchor tx_submitted;
+       struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+       struct usb_anchor rx_submitted;
+
+       struct can_berr_counter bec;
+
+       u8 *cmd_msg_buffer;
+
+       struct mutex usb_8dev_cmd_lock;
+
+};
+
+/* tx frame */
+struct __packed usb_8dev_tx_msg {
+       u8 begin;
+       u8 flags;       /* RTR and EXT_ID flag */
+       __be32 id;      /* upper 3 bits not used */
+       u8 dlc;         /* data length code 0-8 bytes */
+       u8 data[8];     /* 64-bit data */
+       u8 end;
+};
+
+/* rx frame */
+struct __packed usb_8dev_rx_msg {
+       u8 begin;
+       u8 type;                /* frame type */
+       u8 flags;               /* RTR and EXT_ID flag */
+       __be32 id;              /* upper 3 bits not used */
+       u8 dlc;                 /* data length code 0-8 bytes */
+       u8 data[8];             /* 64-bit data */
+       __be32 timestamp;       /* 32-bit timestamp */
+       u8 end;
+};
+
+/* command frame */
+struct __packed usb_8dev_cmd_msg {
+       u8 begin;
+       u8 channel;     /* unkown - always 0 */
+       u8 command;     /* command to execute */
+       u8 opt1;        /* optional parameter / return value */
+       u8 opt2;        /* optional parameter 2 */
+       u8 data[10];    /* optional parameter and data */
+       u8 end;
+};
+
+static int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size)
+{
+       int actual_length;
+
+       return usb_bulk_msg(priv->udev,
+                           usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX),
+                           msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+static int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size,
+                               int *actual_length)
+{
+       return usb_bulk_msg(priv->udev,
+                           usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX),
+                           msg, size, actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+/* Send command to device and receive result.
+ * Command was successful when opt1 = 0.
+ */
+static int usb_8dev_send_cmd(struct usb_8dev_priv *priv,
+                            struct usb_8dev_cmd_msg *out,
+                            struct usb_8dev_cmd_msg *in)
+{
+       int err;
+       int num_bytes_read;
+       struct net_device *netdev;
+
+       netdev = priv->netdev;
+
+       out->begin = USB_8DEV_CMD_START;
+       out->end = USB_8DEV_CMD_END;
+
+       mutex_lock(&priv->usb_8dev_cmd_lock);
+
+       memcpy(priv->cmd_msg_buffer, out,
+               sizeof(struct usb_8dev_cmd_msg));
+
+       err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer,
+                                   sizeof(struct usb_8dev_cmd_msg));
+       if (err < 0) {
+               netdev_err(netdev, "sending command message failed\n");
+               goto failed;
+       }
+
+       err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer,
+                                   sizeof(struct usb_8dev_cmd_msg),
+                                   &num_bytes_read);
+       if (err < 0) {
+               netdev_err(netdev, "no command message answer\n");
+               goto failed;
+       }
+
+       memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg));
+
+       if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END ||
+                       num_bytes_read != 16 || in->opt1 != 0)
+               err = -EPROTO;
+
+failed:
+       mutex_unlock(&priv->usb_8dev_cmd_lock);
+       return err;
+}
+
+/* Send open command to device */
+static int usb_8dev_cmd_open(struct usb_8dev_priv *priv)
+{
+       struct can_bittiming *bt = &priv->can.bittiming;
+       struct usb_8dev_cmd_msg outmsg;
+       struct usb_8dev_cmd_msg inmsg;
+       u32 ctrlmode = priv->can.ctrlmode;
+       u32 flags = USB_8DEV_STATUS_FRAME;
+       __be32 beflags;
+       __be16 bebrp;
+
+       memset(&outmsg, 0, sizeof(outmsg));
+       outmsg.command = USB_8DEV_OPEN;
+       outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+       outmsg.data[0] = bt->prop_seg + bt->phase_seg1;
+       outmsg.data[1] = bt->phase_seg2;
+       outmsg.data[2] = bt->sjw;
+
+       /* BRP */
+       bebrp = cpu_to_be16((u16)bt->brp);
+       memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp));
+
+       /* flags */
+       if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
+               flags |= USB_8DEV_LOOPBACK;
+       if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               flags |= USB_8DEV_SILENT;
+       if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+               flags |= USB_8DEV_DISABLE_AUTO_RESTRANS;
+
+       beflags = cpu_to_be32(flags);
+       memcpy(&outmsg.data[5], &beflags, sizeof(beflags));
+
+       return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Send close command to device */
+static int usb_8dev_cmd_close(struct usb_8dev_priv *priv)
+{
+       struct usb_8dev_cmd_msg inmsg;
+       struct usb_8dev_cmd_msg outmsg = {
+               .channel = 0,
+               .command = USB_8DEV_CLOSE,
+               .opt1 = 0,
+               .opt2 = 0
+       };
+
+       return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Get firmware and hardware version */
+static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res)
+{
+       struct usb_8dev_cmd_msg inmsg;
+       struct usb_8dev_cmd_msg outmsg = {
+               .channel = 0,
+               .command = USB_8DEV_GET_SOFTW_HARDW_VER,
+               .opt1 = 0,
+               .opt2 = 0
+       };
+
+       int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+       if (err)
+               return err;
+
+       *res = be32_to_cpup((__be32 *)inmsg.data);
+
+       return err;
+}
+
+/* Set network device mode
+ *
+ * Maybe we should leave this function empty, because the device
+ * set mode variable with open command.
+ */
+static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+       struct usb_8dev_priv *priv = netdev_priv(netdev);
+       int err = 0;
+
+       switch (mode) {
+       case CAN_MODE_START:
+               err = usb_8dev_cmd_open(priv);
+               if (err)
+                       netdev_warn(netdev, "couldn't start device");
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
+/* Read error/status frames */
+static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
+                               struct usb_8dev_rx_msg *msg)
+{
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       struct net_device_stats *stats = &priv->netdev->stats;
+
+       /* Error message:
+        * byte 0: Status
+        * byte 1: bit   7: Receive Passive
+        * byte 1: bit 0-6: Receive Error Counter
+        * byte 2: Transmit Error Counter
+        * byte 3: Always 0 (maybe reserved for future use)
+        */
+
+       u8 state = msg->data[0];
+       u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK;
+       u8 txerr = msg->data[2];
+       int rx_errors = 0;
+       int tx_errors = 0;
+
+       skb = alloc_can_err_skb(priv->netdev, &cf);
+       if (!skb)
+               return;
+
+       switch (state) {
+       case USB_8DEV_STATUSMSG_OK:
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               cf->can_id |= CAN_ERR_PROT;
+               cf->data[2] = CAN_ERR_PROT_ACTIVE;
+               break;
+       case USB_8DEV_STATUSMSG_BUSOFF:
+               priv->can.state = CAN_STATE_BUS_OFF;
+               cf->can_id |= CAN_ERR_BUSOFF;
+               can_bus_off(priv->netdev);
+               break;
+       case USB_8DEV_STATUSMSG_OVERRUN:
+       case USB_8DEV_STATUSMSG_BUSLIGHT:
+       case USB_8DEV_STATUSMSG_BUSHEAVY:
+               cf->can_id |= CAN_ERR_CRTL;
+               break;
+       default:
+               priv->can.state = CAN_STATE_ERROR_WARNING;
+               cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+               priv->can.can_stats.bus_error++;
+               break;
+       }
+
+       switch (state) {
+       case USB_8DEV_STATUSMSG_OK:
+       case USB_8DEV_STATUSMSG_BUSOFF:
+               break;
+       case USB_8DEV_STATUSMSG_ACK:
+               cf->can_id |= CAN_ERR_ACK;
+               tx_errors = 1;
+               break;
+       case USB_8DEV_STATUSMSG_CRC:
+               cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+                              CAN_ERR_PROT_LOC_CRC_DEL;
+               rx_errors = 1;
+               break;
+       case USB_8DEV_STATUSMSG_BIT0:
+               cf->data[2] |= CAN_ERR_PROT_BIT0;
+               tx_errors = 1;
+               break;
+       case USB_8DEV_STATUSMSG_BIT1:
+               cf->data[2] |= CAN_ERR_PROT_BIT1;
+               tx_errors = 1;
+               break;
+       case USB_8DEV_STATUSMSG_FORM:
+               cf->data[2] |= CAN_ERR_PROT_FORM;
+               rx_errors = 1;
+               break;
+       case USB_8DEV_STATUSMSG_STUFF:
+               cf->data[2] |= CAN_ERR_PROT_STUFF;
+               rx_errors = 1;
+               break;
+       case USB_8DEV_STATUSMSG_OVERRUN:
+               cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+               stats->rx_over_errors++;
+               rx_errors = 1;
+               break;
+       case USB_8DEV_STATUSMSG_BUSLIGHT:
+               priv->can.state = CAN_STATE_ERROR_WARNING;
+               cf->data[1] = (txerr > rxerr) ?
+                       CAN_ERR_CRTL_TX_WARNING :
+                       CAN_ERR_CRTL_RX_WARNING;
+               priv->can.can_stats.error_warning++;
+               break;
+       case USB_8DEV_STATUSMSG_BUSHEAVY:
+               priv->can.state = CAN_STATE_ERROR_PASSIVE;
+               cf->data[1] = (txerr > rxerr) ?
+                       CAN_ERR_CRTL_TX_PASSIVE :
+                       CAN_ERR_CRTL_RX_PASSIVE;
+               priv->can.can_stats.error_passive++;
+               break;
+       default:
+               netdev_warn(priv->netdev,
+                           "Unknown status/error message (%d)\n", state);
+               break;
+       }
+
+       if (tx_errors) {
+               cf->data[2] |= CAN_ERR_PROT_TX;
+               stats->tx_errors++;
+       }
+
+       if (rx_errors)
+               stats->rx_errors++;
+
+       cf->data[6] = txerr;
+       cf->data[7] = rxerr;
+
+       priv->bec.txerr = txerr;
+       priv->bec.rxerr = rxerr;
+
+       netif_rx(skb);
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+}
+
+/* Read data and status frames */
+static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
+                               struct usb_8dev_rx_msg *msg)
+{
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       struct net_device_stats *stats = &priv->netdev->stats;
+
+       if (msg->type == USB_8DEV_TYPE_ERROR_FRAME &&
+                  msg->flags == USB_8DEV_ERR_FLAG) {
+               usb_8dev_rx_err_msg(priv, msg);
+       } else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) {
+               skb = alloc_can_skb(priv->netdev, &cf);
+               if (!skb)
+                       return;
+
+               cf->can_id = be32_to_cpu(msg->id);
+               cf->can_dlc = get_can_dlc(msg->dlc & 0xF);
+
+               if (msg->flags & USB_8DEV_EXTID)
+                       cf->can_id |= CAN_EFF_FLAG;
+
+               if (msg->flags & USB_8DEV_RTR)
+                       cf->can_id |= CAN_RTR_FLAG;
+               else
+                       memcpy(cf->data, msg->data, cf->can_dlc);
+
+               netif_rx(skb);
+
+               stats->rx_packets++;
+               stats->rx_bytes += cf->can_dlc;
+
+               can_led_event(priv->netdev, CAN_LED_EVENT_RX);
+       } else {
+               netdev_warn(priv->netdev, "frame type %d unknown",
+                        msg->type);
+       }
+
+}
+
+/* Callback for reading data from device
+ *
+ * Check urb status, call read function and resubmit urb read operation.
+ */
+static void usb_8dev_read_bulk_callback(struct urb *urb)
+{
+       struct usb_8dev_priv *priv = urb->context;
+       struct net_device *netdev;
+       int retval;
+       int pos = 0;
+
+       netdev = priv->netdev;
+
+       if (!netif_device_present(netdev))
+               return;
+
+       switch (urb->status) {
+       case 0: /* success */
+               break;
+
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+
+       default:
+               netdev_info(netdev, "Rx URB aborted (%d)\n",
+                        urb->status);
+               goto resubmit_urb;
+       }
+
+       while (pos < urb->actual_length) {
+               struct usb_8dev_rx_msg *msg;
+
+               if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) {
+                       netdev_err(priv->netdev, "format error\n");
+                       break;
+               }
+
+               msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos);
+               usb_8dev_rx_can_msg(priv, msg);
+
+               pos += sizeof(struct usb_8dev_rx_msg);
+       }
+
+resubmit_urb:
+       usb_fill_bulk_urb(urb, priv->udev,
+                         usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
+                         urb->transfer_buffer, RX_BUFFER_SIZE,
+                         usb_8dev_read_bulk_callback, priv);
+
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (retval == -ENODEV)
+               netif_device_detach(netdev);
+       else if (retval)
+               netdev_err(netdev,
+                       "failed resubmitting read bulk urb: %d\n", retval);
+}
+
+/* Callback handler for write operations
+ *
+ * Free allocated buffers, check transmit status and
+ * calculate statistic.
+ */
+static void usb_8dev_write_bulk_callback(struct urb *urb)
+{
+       struct usb_8dev_tx_urb_context *context = urb->context;
+       struct usb_8dev_priv *priv;
+       struct net_device *netdev;
+
+       BUG_ON(!context);
+
+       priv = context->priv;
+       netdev = priv->netdev;
+
+       /* free up our allocated buffer */
+       usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+                         urb->transfer_buffer, urb->transfer_dma);
+
+       atomic_dec(&priv->active_tx_urbs);
+
+       if (!netif_device_present(netdev))
+               return;
+
+       if (urb->status)
+               netdev_info(netdev, "Tx URB aborted (%d)\n",
+                        urb->status);
+
+       netdev->stats.tx_packets++;
+       netdev->stats.tx_bytes += context->dlc;
+
+       can_get_echo_skb(netdev, context->echo_index);
+
+       can_led_event(netdev, CAN_LED_EVENT_TX);
+
+       /* Release context */
+       context->echo_index = MAX_TX_URBS;
+
+       netif_wake_queue(netdev);
+}
+
+/* Send data to device */
+static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
+                                     struct net_device *netdev)
+{
+       struct usb_8dev_priv *priv = netdev_priv(netdev);
+       struct net_device_stats *stats = &netdev->stats;
+       struct can_frame *cf = (struct can_frame *) skb->data;
+       struct usb_8dev_tx_msg *msg;
+       struct urb *urb;
+       struct usb_8dev_tx_urb_context *context = NULL;
+       u8 *buf;
+       int i, err;
+       size_t size = sizeof(struct usb_8dev_tx_msg);
+
+       if (can_dropped_invalid_skb(netdev, skb))
+               return NETDEV_TX_OK;
+
+       /* create a URB, and a buffer for it, and copy the data to the URB */
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               netdev_err(netdev, "No memory left for URBs\n");
+               goto nomem;
+       }
+
+       buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC,
+                                &urb->transfer_dma);
+       if (!buf) {
+               netdev_err(netdev, "No memory left for USB buffer\n");
+               goto nomembuf;
+       }
+
+       memset(buf, 0, size);
+
+       msg = (struct usb_8dev_tx_msg *)buf;
+       msg->begin = USB_8DEV_DATA_START;
+       msg->flags = 0x00;
+
+       if (cf->can_id & CAN_RTR_FLAG)
+               msg->flags |= USB_8DEV_RTR;
+
+       if (cf->can_id & CAN_EFF_FLAG)
+               msg->flags |= USB_8DEV_EXTID;
+
+       msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK);
+       msg->dlc = cf->can_dlc;
+       memcpy(msg->data, cf->data, cf->can_dlc);
+       msg->end = USB_8DEV_DATA_END;
+
+       for (i = 0; i < MAX_TX_URBS; i++) {
+               if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+                       context = &priv->tx_contexts[i];
+                       break;
+               }
+       }
+
+       /* May never happen! When this happens we'd more URBs in flight as
+        * allowed (MAX_TX_URBS).
+        */
+       if (!context)
+               goto nofreecontext;
+
+       context->priv = priv;
+       context->echo_index = i;
+       context->dlc = cf->can_dlc;
+
+       usb_fill_bulk_urb(urb, priv->udev,
+                         usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX),
+                         buf, size, usb_8dev_write_bulk_callback, context);
+       urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+       usb_anchor_urb(urb, &priv->tx_submitted);
+
+       can_put_echo_skb(skb, netdev, context->echo_index);
+
+       atomic_inc(&priv->active_tx_urbs);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (unlikely(err))
+               goto failed;
+       else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
+               /* Slow down tx path */
+               netif_stop_queue(netdev);
+
+       /* Release our reference to this URB, the USB core will eventually free
+        * it entirely.
+        */
+       usb_free_urb(urb);
+
+       return NETDEV_TX_OK;
+
+nofreecontext:
+       usb_unanchor_urb(urb);
+       usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+       netdev_warn(netdev, "couldn't find free context");
+
+       return NETDEV_TX_BUSY;
+
+failed:
+       can_free_echo_skb(netdev, context->echo_index);
+
+       usb_unanchor_urb(urb);
+       usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+       atomic_dec(&priv->active_tx_urbs);
+
+       if (err == -ENODEV)
+               netif_device_detach(netdev);
+       else
+               netdev_warn(netdev, "failed tx_urb %d\n", err);
+
+nomembuf:
+       usb_free_urb(urb);
+
+nomem:
+       dev_kfree_skb(skb);
+       stats->tx_dropped++;
+
+       return NETDEV_TX_OK;
+}
+
+static int usb_8dev_get_berr_counter(const struct net_device *netdev,
+                                    struct can_berr_counter *bec)
+{
+       struct usb_8dev_priv *priv = netdev_priv(netdev);
+
+       bec->txerr = priv->bec.txerr;
+       bec->rxerr = priv->bec.rxerr;
+
+       return 0;
+}
+
+/* Start USB device */
+static int usb_8dev_start(struct usb_8dev_priv *priv)
+{
+       struct net_device *netdev = priv->netdev;
+       int err, i;
+
+       for (i = 0; i < MAX_RX_URBS; i++) {
+               struct urb *urb = NULL;
+               u8 *buf;
+
+               /* create a URB, and a buffer for it */
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       netdev_err(netdev, "No memory left for URBs\n");
+                       err = -ENOMEM;
+                       break;
+               }
+
+               buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
+                                        &urb->transfer_dma);
+               if (!buf) {
+                       netdev_err(netdev, "No memory left for USB buffer\n");
+                       usb_free_urb(urb);
+                       err = -ENOMEM;
+                       break;
+               }
+
+               usb_fill_bulk_urb(urb, priv->udev,
+                                 usb_rcvbulkpipe(priv->udev,
+                                                 USB_8DEV_ENDP_DATA_RX),
+                                 buf, RX_BUFFER_SIZE,
+                                 usb_8dev_read_bulk_callback, priv);
+               urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               usb_anchor_urb(urb, &priv->rx_submitted);
+
+               err = usb_submit_urb(urb, GFP_KERNEL);
+               if (err) {
+                       usb_unanchor_urb(urb);
+                       usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
+                                         urb->transfer_dma);
+                       break;
+               }
+
+               /* Drop reference, USB core will take care of freeing it */
+               usb_free_urb(urb);
+       }
+
+       /* Did we submit any URBs */
+       if (i == 0) {
+               netdev_warn(netdev, "couldn't setup read URBs\n");
+               return err;
+       }
+
+       /* Warn if we've couldn't transmit all the URBs */
+       if (i < MAX_RX_URBS)
+               netdev_warn(netdev, "rx performance may be slow\n");
+
+       err = usb_8dev_cmd_open(priv);
+       if (err)
+               goto failed;
+
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+       return 0;
+
+failed:
+       if (err == -ENODEV)
+               netif_device_detach(priv->netdev);
+
+       netdev_warn(netdev, "couldn't submit control: %d\n", err);
+
+       return err;
+}
+
+/* Open USB device */
+static int usb_8dev_open(struct net_device *netdev)
+{
+       struct usb_8dev_priv *priv = netdev_priv(netdev);
+       int err;
+
+       /* common open */
+       err = open_candev(netdev);
+       if (err)
+               return err;
+
+       can_led_event(netdev, CAN_LED_EVENT_OPEN);
+
+       /* finally start device */
+       err = usb_8dev_start(priv);
+       if (err) {
+               if (err == -ENODEV)
+                       netif_device_detach(priv->netdev);
+
+               netdev_warn(netdev, "couldn't start device: %d\n",
+                        err);
+
+               close_candev(netdev);
+
+               return err;
+       }
+
+       netif_start_queue(netdev);
+
+       return 0;
+}
+
+static void unlink_all_urbs(struct usb_8dev_priv *priv)
+{
+       int i;
+
+       usb_kill_anchored_urbs(&priv->rx_submitted);
+
+       usb_kill_anchored_urbs(&priv->tx_submitted);
+       atomic_set(&priv->active_tx_urbs, 0);
+
+       for (i = 0; i < MAX_TX_URBS; i++)
+               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+}
+
+/* Close USB device */
+static int usb_8dev_close(struct net_device *netdev)
+{
+       struct usb_8dev_priv *priv = netdev_priv(netdev);
+       int err = 0;
+
+       /* Send CLOSE command to CAN controller */
+       err = usb_8dev_cmd_close(priv);
+       if (err)
+               netdev_warn(netdev, "couldn't stop device");
+
+       priv->can.state = CAN_STATE_STOPPED;
+
+       netif_stop_queue(netdev);
+
+       /* Stop polling */
+       unlink_all_urbs(priv);
+
+       close_candev(netdev);
+
+       can_led_event(netdev, CAN_LED_EVENT_STOP);
+
+       return err;
+}
+
+static const struct net_device_ops usb_8dev_netdev_ops = {
+       .ndo_open = usb_8dev_open,
+       .ndo_stop = usb_8dev_close,
+       .ndo_start_xmit = usb_8dev_start_xmit,
+};
+
+static const struct can_bittiming_const usb_8dev_bittiming_const = {
+       .name = "usb_8dev",
+       .tseg1_min = 1,
+       .tseg1_max = 16,
+       .tseg2_min = 1,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 1024,
+       .brp_inc = 1,
+};
+
+/* Probe USB device
+ *
+ * Check device and firmware.
+ * Set supported modes and bittiming constants.
+ * Allocate some memory.
+ */
+static int usb_8dev_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       struct net_device *netdev;
+       struct usb_8dev_priv *priv;
+       int i, err = -ENOMEM;
+       u32 version;
+       char buf[18];
+       struct usb_device *usbdev = interface_to_usbdev(intf);
+
+       /* product id looks strange, better we also check iProduct string */
+       if (usb_string(usbdev, usbdev->descriptor.iProduct, buf,
+                      sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) {
+               dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n");
+               return -ENODEV;
+       }
+
+       netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS);
+       if (!netdev) {
+               dev_err(&intf->dev, "Couldn't alloc candev\n");
+               return -ENOMEM;
+       }
+
+       priv = netdev_priv(netdev);
+
+       priv->udev = usbdev;
+       priv->netdev = netdev;
+
+       priv->can.state = CAN_STATE_STOPPED;
+       priv->can.clock.freq = USB_8DEV_ABP_CLOCK;
+       priv->can.bittiming_const = &usb_8dev_bittiming_const;
+       priv->can.do_set_mode = usb_8dev_set_mode;
+       priv->can.do_get_berr_counter = usb_8dev_get_berr_counter;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+                                     CAN_CTRLMODE_LISTENONLY |
+                                     CAN_CTRLMODE_ONE_SHOT;
+
+       netdev->netdev_ops = &usb_8dev_netdev_ops;
+
+       netdev->flags |= IFF_ECHO; /* we support local echo */
+
+       init_usb_anchor(&priv->rx_submitted);
+
+       init_usb_anchor(&priv->tx_submitted);
+       atomic_set(&priv->active_tx_urbs, 0);
+
+       for (i = 0; i < MAX_TX_URBS; i++)
+               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+       priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
+                                     GFP_KERNEL);
+       if (!priv->cmd_msg_buffer) {
+               netdev_err(netdev, "Couldn't alloc Tx buffer\n");
+               goto cleanup_candev;
+       }
+
+       usb_set_intfdata(intf, priv);
+
+       SET_NETDEV_DEV(netdev, &intf->dev);
+
+       mutex_init(&priv->usb_8dev_cmd_lock);
+
+       err = register_candev(netdev);
+       if (err) {
+               netdev_err(netdev,
+                       "couldn't register CAN device: %d\n", err);
+               goto cleanup_cmd_msg_buffer;
+       }
+
+       err = usb_8dev_cmd_version(priv, &version);
+       if (err) {
+               netdev_err(netdev, "can't get firmware version\n");
+               goto cleanup_cmd_msg_buffer;
+       } else {
+               netdev_info(netdev,
+                        "firmware: %d.%d, hardware: %d.%d\n",
+                        (version>>24) & 0xff, (version>>16) & 0xff,
+                        (version>>8) & 0xff, version & 0xff);
+       }
+
+       devm_can_led_init(netdev);
+
+       return 0;
+
+cleanup_cmd_msg_buffer:
+       kfree(priv->cmd_msg_buffer);
+
+cleanup_candev:
+       free_candev(netdev);
+
+       return err;
+
+}
+
+/* Called by the usb core when driver is unloaded or device is removed */
+static void usb_8dev_disconnect(struct usb_interface *intf)
+{
+       struct usb_8dev_priv *priv = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+
+       if (priv) {
+               netdev_info(priv->netdev, "device disconnected\n");
+
+               unregister_netdev(priv->netdev);
+               free_candev(priv->netdev);
+
+               unlink_all_urbs(priv);
+       }
+
+}
+
+static struct usb_driver usb_8dev_driver = {
+       .name =         "usb_8dev",
+       .probe =        usb_8dev_probe,
+       .disconnect =   usb_8dev_disconnect,
+       .id_table =     usb_8dev_table,
+};
+
+module_usb_driver(usb_8dev_driver);
+
+MODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>");
+MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces");
+MODULE_LICENSE("GPL v2");
index 021d69c5d9bc951797ede8e72dde15bad706613b..29e272cc7a984f79cc3d6815b76deacb18b70abb 100644 (file)
@@ -1448,10 +1448,10 @@ static int e100_set_settings(struct net_device *dev,
 static void e100_get_drvinfo(struct net_device *dev,
                             struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1);
-       strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1);
-       strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1);
-       strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1);
+       strlcpy(info->driver, "ETRAX 100LX", sizeof(info->driver));
+       strlcpy(info->version, "$Revision: 1.31 $", sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
 }
 
 static int e100_nway_reset(struct net_device *dev)
index 325391d19badb8366f27f726dbee042d1fe430ad..7a54ec04b4181210961f2819c7fca1e260cb7661 100644 (file)
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -66,36 +68,30 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
 {
        int i;
        int ret;
+       unsigned long timeout;
 
-       /*
-        * Set all ports to the disabled state.
-        */
+       /* Set all ports to the disabled state. */
        for (i = 0; i < 6; i++) {
                ret = REG_READ(REG_PORT(i), 0x04);
                REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
        }
 
-       /*
-        * Wait for transmit queues to drain.
-        */
-       msleep(2);
+       /* Wait for transmit queues to drain. */
+       usleep_range(2000, 4000);
 
-       /*
-        * Reset the switch.
-        */
+       /* Reset the switch. */
        REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
 
-       /*
-        * Wait up to one second for reset to complete.
-        */
-       for (i = 0; i < 1000; i++) {
+       /* Wait up to one second for reset to complete. */
+       timeout = jiffies + 1 * HZ;
+       while (time_before(jiffies, timeout)) {
                ret = REG_READ(REG_GLOBAL, 0x00);
                if ((ret & 0x8000) == 0x0000)
                        break;
 
-               msleep(1);
+               usleep_range(1000, 2000);
        }
-       if (i == 1000)
+       if (time_after(jiffies, timeout))
                return -ETIMEDOUT;
 
        return 0;
@@ -103,15 +99,13 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
 
 static int mv88e6060_setup_global(struct dsa_switch *ds)
 {
-       /*
-        * Disable discarding of frames with excessive collisions,
+       /* Disable discarding of frames with excessive collisions,
         * set the maximum frame size to 1536 bytes, and mask all
         * interrupt sources.
         */
        REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
 
-       /*
-        * Enable automatic address learning, set the address
+       /* Enable automatic address learning, set the address
         * database size to 1024 entries, and set the default aging
         * time to 5 minutes.
         */
@@ -124,16 +118,14 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
 {
        int addr = REG_PORT(p);
 
-       /*
-        * Do not force flow control, disable Ingress and Egress
+       /* Do not force flow control, disable Ingress and Egress
         * Header tagging, disable VLAN tunneling, and set the port
         * state to Forwarding.  Additionally, if this is the CPU
         * port, enable Ingress and Egress Trailer tagging mode.
         */
        REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ?  0x4103 : 0x0003);
 
-       /*
-        * Port based VLAN map: give each port its own address
+       /* Port based VLAN map: give each port its own address
         * database, allow the CPU port to talk to each of the 'real'
         * ports, and allow each of the 'real' ports to only talk to
         * the CPU port.
@@ -144,8 +136,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
                                ds->phys_port_mask :
                                (1 << ds->dst->cpu_port)));
 
-       /*
-        * Port Association Vector: when learning source addresses
+       /* Port Association Vector: when learning source addresses
         * of packets, add the address to the address database using
         * a port bitmap that has only the bit for this port set and
         * the other bits clear.
@@ -245,7 +236,7 @@ static void mv88e6060_poll_link(struct dsa_switch *ds)
 
                if (!link) {
                        if (netif_carrier_ok(dev)) {
-                               printk(KERN_INFO "%s: link down\n", dev->name);
+                               netdev_info(dev, "link down\n");
                                netif_carrier_off(dev);
                        }
                        continue;
@@ -256,10 +247,11 @@ static void mv88e6060_poll_link(struct dsa_switch *ds)
                fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
 
                if (!netif_carrier_ok(dev)) {
-                       printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
-                                        "flow control %sabled\n", dev->name,
-                                        speed, duplex ? "full" : "half",
-                                        fc ? "en" : "dis");
+                       netdev_info(dev,
+                                   "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+                                   speed,
+                                   duplex ? "full" : "half",
+                                   fc ? "en" : "dis");
                        netif_carrier_on(dev);
                }
        }
index c17c75b9f531f49c661b132267653e2984212059..41ee5b6ae91751239d81e4613f336aff02fbff84 100644 (file)
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -50,36 +52,30 @@ static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
 {
        int i;
        int ret;
+       unsigned long timeout;
 
-       /*
-        * Set all ports to the disabled state.
-        */
+       /* Set all ports to the disabled state. */
        for (i = 0; i < 8; i++) {
                ret = REG_READ(REG_PORT(i), 0x04);
                REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
        }
 
-       /*
-        * Wait for transmit queues to drain.
-        */
-       msleep(2);
+       /* Wait for transmit queues to drain. */
+       usleep_range(2000, 4000);
 
-       /*
-        * Reset the switch.
-        */
+       /* Reset the switch. */
        REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
 
-       /*
-        * Wait up to one second for reset to complete.
-        */
-       for (i = 0; i < 1000; i++) {
+       /* Wait up to one second for reset to complete. */
+       timeout = jiffies + 1 * HZ;
+       while (time_before(jiffies, timeout)) {
                ret = REG_READ(REG_GLOBAL, 0x00);
                if ((ret & 0xc800) == 0xc800)
                        break;
 
-               msleep(1);
+               usleep_range(1000, 2000);
        }
-       if (i == 1000)
+       if (time_after(jiffies, timeout))
                return -ETIMEDOUT;
 
        return 0;
@@ -90,54 +86,45 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
        int ret;
        int i;
 
-       /*
-        * Disable the PHY polling unit (since there won't be any
+       /* Disable the PHY polling unit (since there won't be any
         * external PHYs to poll), don't discard packets with
         * excessive collisions, and mask all interrupt sources.
         */
        REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
 
-       /*
-        * Set the default address aging time to 5 minutes, and
+       /* Set the default address aging time to 5 minutes, and
         * enable address learn messages to be sent to all message
         * ports.
         */
        REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
 
-       /*
-        * Configure the priority mapping registers.
-        */
+       /* Configure the priority mapping registers. */
        ret = mv88e6xxx_config_prio(ds);
        if (ret < 0)
                return ret;
 
-       /*
-        * Configure the upstream port, and configure the upstream
+       /* Configure the upstream port, and configure the upstream
         * port as the port to which ingress and egress monitor frames
         * are to be sent.
         */
        REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
 
-       /*
-        * Disable remote management for now, and set the switch's
+       /* Disable remote management for now, and set the switch's
         * DSA device number.
         */
        REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
 
-       /*
-        * Send all frames with destination addresses matching
+       /* Send all frames with destination addresses matching
         * 01:80:c2:00:00:2x to the CPU port.
         */
        REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
 
-       /*
-        * Send all frames with destination addresses matching
+       /* Send all frames with destination addresses matching
         * 01:80:c2:00:00:0x to the CPU port.
         */
        REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
 
-       /*
-        * Disable the loopback filter, disable flow control
+       /* Disable the loopback filter, disable flow control
         * messages, disable flood broadcast override, disable
         * removing of provider tags, disable ATU age violation
         * interrupts, disable tag flow control, force flow
@@ -146,9 +133,7 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
         */
        REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
 
-       /*
-        * Program the DSA routing table.
-        */
+       /* Program the DSA routing table. */
        for (i = 0; i < 32; i++) {
                int nexthop;
 
@@ -159,33 +144,24 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
                REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
        }
 
-       /*
-        * Clear all trunk masks.
-        */
+       /* Clear all trunk masks. */
        for (i = 0; i < 8; i++)
                REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
 
-       /*
-        * Clear all trunk mappings.
-        */
+       /* Clear all trunk mappings. */
        for (i = 0; i < 16; i++)
                REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
 
-       /*
-        * Disable ingress rate limiting by resetting all ingress
+       /* Disable ingress rate limiting by resetting all ingress
         * rate limit registers to their initial state.
         */
        for (i = 0; i < 6; i++)
                REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
 
-       /*
-        * Initialise cross-chip port VLAN table to reset defaults.
-        */
+       /* Initialise cross-chip port VLAN table to reset defaults. */
        REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
 
-       /*
-        * Clear the priority override table.
-        */
+       /* Clear the priority override table. */
        for (i = 0; i < 16; i++)
                REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
 
@@ -199,8 +175,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
        int addr = REG_PORT(p);
        u16 val;
 
-       /*
-        * MAC Forcing register: don't force link, speed, duplex
+       /* MAC Forcing register: don't force link, speed, duplex
         * or flow control state to any particular values on physical
         * ports, but force the CPU port and all DSA ports to 1000 Mb/s
         * full duplex.
@@ -210,15 +185,13 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
        else
                REG_WRITE(addr, 0x01, 0x0003);
 
-       /*
-        * Do not limit the period of time that this port can be
+       /* Do not limit the period of time that this port can be
         * paused for by the remote end or the period of time that
         * this port can pause the remote end.
         */
        REG_WRITE(addr, 0x02, 0x0000);
 
-       /*
-        * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
+       /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
         * disable Header mode, enable IGMP/MLD snooping, disable VLAN
         * tunneling, determine priority by looking at 802.1p and IP
         * priority fields (IP prio has precedence), and set STP state
@@ -245,14 +218,12 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
                val |= 0x000c;
        REG_WRITE(addr, 0x04, val);
 
-       /*
-        * Port Control 1: disable trunking.  Also, if this is the
+       /* Port Control 1: disable trunking.  Also, if this is the
         * CPU port, enable learn messages to be sent to this port.
         */
        REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
 
-       /*
-        * Port based VLAN map: give each port its own address
+       /* Port based VLAN map: give each port its own address
         * database, allow the CPU port to talk to each of the 'real'
         * ports, and allow each of the 'real' ports to only talk to
         * the upstream port.
@@ -264,14 +235,12 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
                val |= 1 << dsa_upstream_port(ds);
        REG_WRITE(addr, 0x06, val);
 
-       /*
-        * Default VLAN ID and priority: don't set a default VLAN
+       /* Default VLAN ID and priority: don't set a default VLAN
         * ID, and set the default packet priority to zero.
         */
        REG_WRITE(addr, 0x07, 0x0000);
 
-       /*
-        * Port Control 2: don't force a good FCS, set the maximum
+       /* Port Control 2: don't force a good FCS, set the maximum
         * frame size to 10240 bytes, don't let the switch add or
         * strip 802.1q tags, don't discard tagged or untagged frames
         * on this port, do a destination address lookup on all
@@ -281,48 +250,36 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
         */
        REG_WRITE(addr, 0x08, 0x2080);
 
-       /*
-        * Egress rate control: disable egress rate control.
-        */
+       /* Egress rate control: disable egress rate control. */
        REG_WRITE(addr, 0x09, 0x0001);
 
-       /*
-        * Egress rate control 2: disable egress rate control.
-        */
+       /* Egress rate control 2: disable egress rate control. */
        REG_WRITE(addr, 0x0a, 0x0000);
 
-       /*
-        * Port Association Vector: when learning source addresses
+       /* Port Association Vector: when learning source addresses
         * of packets, add the address to the address database using
         * a port bitmap that has only the bit for this port set and
         * the other bits clear.
         */
        REG_WRITE(addr, 0x0b, 1 << p);
 
-       /*
-        * Port ATU control: disable limiting the number of address
+       /* Port ATU control: disable limiting the number of address
         * database entries that this port is allowed to use.
         */
        REG_WRITE(addr, 0x0c, 0x0000);
 
-       /*
-        * Priorit Override: disable DA, SA and VTU priority override.
-        */
+       /* Priority Override: disable DA, SA and VTU priority override. */
        REG_WRITE(addr, 0x0d, 0x0000);
 
-       /*
-        * Port Ethertype: use the Ethertype DSA Ethertype value.
-        */
+       /* Port Ethertype: use the Ethertype DSA Ethertype value. */
        REG_WRITE(addr, 0x0f, ETH_P_EDSA);
 
-       /*
-        * Tag Remap: use an identity 802.1p prio -> switch prio
+       /* Tag Remap: use an identity 802.1p prio -> switch prio
         * mapping.
         */
        REG_WRITE(addr, 0x18, 0x3210);
 
-       /*
-        * Tag Remap 2: use an identity 802.1p prio -> switch prio
+       /* Tag Remap 2: use an identity 802.1p prio -> switch prio
         * mapping.
         */
        REG_WRITE(addr, 0x19, 0x7654);
index 55888b06d8b47af7c90564027db08e2f54bf512d..dadfafba64e9ac0aad3de55d84e5bdea3ceb00a0 100644 (file)
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -15,9 +17,7 @@
 #include <net/dsa.h>
 #include "mv88e6xxx.h"
 
-/*
- * Switch product IDs
- */
+/* Switch product IDs */
 #define ID_6085                0x04a0
 #define ID_6095                0x0950
 #define ID_6131                0x1060
@@ -44,36 +44,30 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds)
 {
        int i;
        int ret;
+       unsigned long timeout;
 
-       /*
-        * Set all ports to the disabled state.
-        */
+       /* Set all ports to the disabled state. */
        for (i = 0; i < 11; i++) {
                ret = REG_READ(REG_PORT(i), 0x04);
                REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
        }
 
-       /*
-        * Wait for transmit queues to drain.
-        */
-       msleep(2);
+       /* Wait for transmit queues to drain. */
+       usleep_range(2000, 4000);
 
-       /*
-        * Reset the switch.
-        */
+       /* Reset the switch. */
        REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
 
-       /*
-        * Wait up to one second for reset to complete.
-        */
-       for (i = 0; i < 1000; i++) {
+       /* Wait up to one second for reset to complete. */
+       timeout = jiffies + 1 * HZ;
+       while (time_before(jiffies, timeout)) {
                ret = REG_READ(REG_GLOBAL, 0x00);
                if ((ret & 0xc800) == 0xc800)
                        break;
 
-               msleep(1);
+               usleep_range(1000, 2000);
        }
-       if (i == 1000)
+       if (time_after(jiffies, timeout))
                return -ETIMEDOUT;
 
        return 0;
@@ -84,42 +78,34 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
        int ret;
        int i;
 
-       /*
-        * Enable the PHY polling unit, don't discard packets with
+       /* Enable the PHY polling unit, don't discard packets with
         * excessive collisions, use a weighted fair queueing scheme
         * to arbitrate between packet queues, set the maximum frame
         * size to 1632, and mask all interrupt sources.
         */
        REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
 
-       /*
-        * Set the default address aging time to 5 minutes, and
+       /* Set the default address aging time to 5 minutes, and
         * enable address learn messages to be sent to all message
         * ports.
         */
        REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
 
-       /*
-        * Configure the priority mapping registers.
-        */
+       /* Configure the priority mapping registers. */
        ret = mv88e6xxx_config_prio(ds);
        if (ret < 0)
                return ret;
 
-       /*
-        * Set the VLAN ethertype to 0x8100.
-        */
+       /* Set the VLAN ethertype to 0x8100. */
        REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
 
-       /*
-        * Disable ARP mirroring, and configure the upstream port as
+       /* Disable ARP mirroring, and configure the upstream port as
         * the port to which ingress and egress monitor frames are to
         * be sent.
         */
        REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
 
-       /*
-        * Disable cascade port functionality unless this device
+       /* Disable cascade port functionality unless this device
         * is used in a cascade configuration, and set the switch's
         * DSA device number.
         */
@@ -128,23 +114,19 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
        else
                REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
 
-       /*
-        * Send all frames with destination addresses matching
+       /* Send all frames with destination addresses matching
         * 01:80:c2:00:00:0x to the CPU port.
         */
        REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
 
-       /*
-        * Ignore removed tag data on doubly tagged packets, disable
+       /* Ignore removed tag data on doubly tagged packets, disable
         * flow control messages, force flow control priority to the
         * highest, and send all special multicast frames to the CPU
         * port at the highest priority.
         */
        REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
 
-       /*
-        * Program the DSA routing table.
-        */
+       /* Program the DSA routing table. */
        for (i = 0; i < 32; i++) {
                int nexthop;
 
@@ -155,20 +137,15 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
                REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
        }
 
-       /*
-        * Clear all trunk masks.
-        */
+       /* Clear all trunk masks. */
        for (i = 0; i < 8; i++)
                REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
 
-       /*
-        * Clear all trunk mappings.
-        */
+       /* Clear all trunk mappings. */
        for (i = 0; i < 16; i++)
                REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
 
-       /*
-        * Force the priority of IGMP/MLD snoop frames and ARP frames
+       /* Force the priority of IGMP/MLD snoop frames and ARP frames
         * to the highest setting.
         */
        REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
@@ -182,8 +159,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
        int addr = REG_PORT(p);
        u16 val;
 
-       /*
-        * MAC Forcing register: don't force link, speed, duplex
+       /* MAC Forcing register: don't force link, speed, duplex
         * or flow control state to any particular values on physical
         * ports, but force the CPU port and all DSA ports to 1000 Mb/s
         * (100 Mb/s on 6085) full duplex.
@@ -196,8 +172,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
        else
                REG_WRITE(addr, 0x01, 0x0003);
 
-       /*
-        * Port Control: disable Core Tag, disable Drop-on-Lock,
+       /* Port Control: disable Core Tag, disable Drop-on-Lock,
         * transmit frames unmodified, disable Header mode,
         * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
         * tunneling, determine priority by looking at 802.1p and
@@ -214,8 +189,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
        val = 0x0433;
        if (p == dsa_upstream_port(ds)) {
                val |= 0x0104;
-               /*
-                * On 6085, unknown multicast forward is controlled
+               /* On 6085, unknown multicast forward is controlled
                 * here rather than in Port Control 2 register.
                 */
                if (ps->id == ID_6085)
@@ -225,14 +199,12 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
                val |= 0x0100;
        REG_WRITE(addr, 0x04, val);
 
-       /*
-        * Port Control 1: disable trunking.  Also, if this is the
+       /* Port Control 1: disable trunking.  Also, if this is the
         * CPU port, enable learn messages to be sent to this port.
         */
        REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
 
-       /*
-        * Port based VLAN map: give each port its own address
+       /* Port based VLAN map: give each port its own address
         * database, allow the CPU port to talk to each of the 'real'
         * ports, and allow each of the 'real' ports to only talk to
         * the upstream port.
@@ -244,14 +216,12 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
                val |= 1 << dsa_upstream_port(ds);
        REG_WRITE(addr, 0x06, val);
 
-       /*
-        * Default VLAN ID and priority: don't set a default VLAN
+       /* Default VLAN ID and priority: don't set a default VLAN
         * ID, and set the default packet priority to zero.
         */
        REG_WRITE(addr, 0x07, 0x0000);
 
-       /*
-        * Port Control 2: don't force a good FCS, don't use
+       /* Port Control 2: don't force a good FCS, don't use
         * VLAN-based, source address-based or destination
         * address-based priority overrides, don't let the switch
         * add or strip 802.1q tags, don't discard tagged or
@@ -264,8 +234,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
         * forwarding of unknown multicast addresses.
         */
        if (ps->id == ID_6085)
-               /*
-                * on 6085, bits 3:0 are reserved, bit 6 control ARP
+               /* on 6085, bits 3:0 are reserved, bit 6 control ARP
                 * mirroring, and multicast forward is handled in
                 * Port Control register.
                 */
@@ -277,32 +246,25 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
                REG_WRITE(addr, 0x08, val);
        }
 
-       /*
-        * Rate Control: disable ingress rate limiting.
-        */
+       /* Rate Control: disable ingress rate limiting. */
        REG_WRITE(addr, 0x09, 0x0000);
 
-       /*
-        * Rate Control 2: disable egress rate limiting.
-        */
+       /* Rate Control 2: disable egress rate limiting. */
        REG_WRITE(addr, 0x0a, 0x0000);
 
-       /*
-        * Port Association Vector: when learning source addresses
+       /* Port Association Vector: when learning source addresses
         * of packets, add the address to the address database using
         * a port bitmap that has only the bit for this port set and
         * the other bits clear.
         */
        REG_WRITE(addr, 0x0b, 1 << p);
 
-       /*
-        * Tag Remap: use an identity 802.1p prio -> switch prio
+       /* Tag Remap: use an identity 802.1p prio -> switch prio
         * mapping.
         */
        REG_WRITE(addr, 0x18, 0x3210);
 
-       /*
-        * Tag Remap 2: use an identity 802.1p prio -> switch prio
+       /* Tag Remap 2: use an identity 802.1p prio -> switch prio
         * mapping.
         */
        REG_WRITE(addr, 0x19, 0x7654);
index a2c62c2f30ee40f7ecb11d460958cae0f5c94e80..17314ed9456d32c961aea31db10a650a2ffb1392 100644 (file)
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -15,8 +17,7 @@
 #include <net/dsa.h>
 #include "mv88e6xxx.h"
 
-/*
- * If the switch's ADDR[4:0] strap pins are strapped to zero, it will
+/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
  * use all 32 SMI bus addresses on its SMI bus, and all switch registers
  * will be directly accessible on some {device address,register address}
  * pair.  If the ADDR[4:0] pins are not strapped to zero, the switch
@@ -48,30 +49,22 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
        if (sw_addr == 0)
                return mdiobus_read(bus, addr, reg);
 
-       /*
-        * Wait for the bus to become free.
-        */
+       /* Wait for the bus to become free. */
        ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
        if (ret < 0)
                return ret;
 
-       /*
-        * Transmit the read command.
-        */
+       /* Transmit the read command. */
        ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg);
        if (ret < 0)
                return ret;
 
-       /*
-        * Wait for the read command to complete.
-        */
+       /* Wait for the read command to complete. */
        ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
        if (ret < 0)
                return ret;
 
-       /*
-        * Read the data.
-        */
+       /* Read the data. */
        ret = mdiobus_read(bus, sw_addr, 1);
        if (ret < 0)
                return ret;
@@ -100,30 +93,22 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
        if (sw_addr == 0)
                return mdiobus_write(bus, addr, reg, val);
 
-       /*
-        * Wait for the bus to become free.
-        */
+       /* Wait for the bus to become free. */
        ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
        if (ret < 0)
                return ret;
 
-       /*
-        * Transmit the data to write.
-        */
+       /* Transmit the data to write. */
        ret = mdiobus_write(bus, sw_addr, 1, val);
        if (ret < 0)
                return ret;
 
-       /*
-        * Transmit the write command.
-        */
+       /* Transmit the write command. */
        ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg);
        if (ret < 0)
                return ret;
 
-       /*
-        * Wait for the write command to complete.
-        */
+       /* Wait for the write command to complete. */
        ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
        if (ret < 0)
                return ret;
@@ -146,9 +131,7 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
 
 int mv88e6xxx_config_prio(struct dsa_switch *ds)
 {
-       /*
-        * Configure the IP ToS mapping registers.
-        */
+       /* Configure the IP ToS mapping registers. */
        REG_WRITE(REG_GLOBAL, 0x10, 0x0000);
        REG_WRITE(REG_GLOBAL, 0x11, 0x0000);
        REG_WRITE(REG_GLOBAL, 0x12, 0x5555);
@@ -158,9 +141,7 @@ int mv88e6xxx_config_prio(struct dsa_switch *ds)
        REG_WRITE(REG_GLOBAL, 0x16, 0xffff);
        REG_WRITE(REG_GLOBAL, 0x17, 0xffff);
 
-       /*
-        * Configure the IEEE 802.1p priority mapping register.
-        */
+       /* Configure the IEEE 802.1p priority mapping register. */
        REG_WRITE(REG_GLOBAL, 0x18, 0xfa41);
 
        return 0;
@@ -183,14 +164,10 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
        for (i = 0; i < 6; i++) {
                int j;
 
-               /*
-                * Write the MAC address byte.
-                */
+               /* Write the MAC address byte. */
                REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]);
 
-               /*
-                * Wait for the write to complete.
-                */
+               /* Wait for the write to complete. */
                for (j = 0; j < 16; j++) {
                        ret = REG_READ(REG_GLOBAL2, 0x0d);
                        if ((ret & 0x8000) == 0)
@@ -221,16 +198,17 @@ int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val)
 static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
 {
        int ret;
-       int i;
+       unsigned long timeout;
 
        ret = REG_READ(REG_GLOBAL, 0x04);
        REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000);
 
-       for (i = 0; i < 1000; i++) {
-               ret = REG_READ(REG_GLOBAL, 0x00);
-               msleep(1);
-               if ((ret & 0xc000) != 0xc000)
-                       return 0;
+       timeout = jiffies + 1 * HZ;
+       while (time_before(jiffies, timeout)) {
+               ret = REG_READ(REG_GLOBAL, 0x00);
+               usleep_range(1000, 2000);
+               if ((ret & 0xc000) != 0xc000)
+                       return 0;
        }
 
        return -ETIMEDOUT;
@@ -239,16 +217,17 @@ static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
 static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
 {
        int ret;
-       int i;
+       unsigned long timeout;
 
        ret = REG_READ(REG_GLOBAL, 0x04);
        REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000);
 
-       for (i = 0; i < 1000; i++) {
-               ret = REG_READ(REG_GLOBAL, 0x00);
-               msleep(1);
-               if ((ret & 0xc000) == 0xc000)
-                       return 0;
+       timeout = jiffies + 1 * HZ;
+       while (time_before(jiffies, timeout)) {
+               ret = REG_READ(REG_GLOBAL, 0x00);
+               usleep_range(1000, 2000);
+               if ((ret & 0xc000) == 0xc000)
+                       return 0;
        }
 
        return -ETIMEDOUT;
@@ -260,11 +239,11 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
 
        ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
        if (mutex_trylock(&ps->ppu_mutex)) {
-               struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
+               struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
 
-               if (mv88e6xxx_ppu_enable(ds) == 0)
-                       ps->ppu_disabled = 0;
-               mutex_unlock(&ps->ppu_mutex);
+               if (mv88e6xxx_ppu_enable(ds) == 0)
+                       ps->ppu_disabled = 0;
+               mutex_unlock(&ps->ppu_mutex);
        }
 }
 
@@ -282,22 +261,21 @@ static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
 
        mutex_lock(&ps->ppu_mutex);
 
-       /*
-        * If the PHY polling unit is enabled, disable it so that
+       /* If the PHY polling unit is enabled, disable it so that
         * we can access the PHY registers.  If it was already
         * disabled, cancel the timer that is going to re-enable
         * it.
         */
        if (!ps->ppu_disabled) {
-               ret = mv88e6xxx_ppu_disable(ds);
-               if (ret < 0) {
-                       mutex_unlock(&ps->ppu_mutex);
-                       return ret;
-               }
-               ps->ppu_disabled = 1;
+               ret = mv88e6xxx_ppu_disable(ds);
+               if (ret < 0) {
+                       mutex_unlock(&ps->ppu_mutex);
+                       return ret;
+               }
+               ps->ppu_disabled = 1;
        } else {
-               del_timer(&ps->ppu_timer);
-               ret = 0;
+               del_timer(&ps->ppu_timer);
+               ret = 0;
        }
 
        return ret;
@@ -307,9 +285,7 @@ static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
 {
        struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
 
-       /*
-        * Schedule a timer to re-enable the PHY polling unit.
-        */
+       /* Schedule a timer to re-enable the PHY polling unit. */
        mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
        mutex_unlock(&ps->ppu_mutex);
 }
@@ -331,8 +307,8 @@ int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
 
        ret = mv88e6xxx_ppu_access_get(ds);
        if (ret >= 0) {
-               ret = mv88e6xxx_reg_read(ds, addr, regnum);
-               mv88e6xxx_ppu_access_put(ds);
+               ret = mv88e6xxx_reg_read(ds, addr, regnum);
+               mv88e6xxx_ppu_access_put(ds);
        }
 
        return ret;
@@ -345,8 +321,8 @@ int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
 
        ret = mv88e6xxx_ppu_access_get(ds);
        if (ret >= 0) {
-               ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
-               mv88e6xxx_ppu_access_put(ds);
+               ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
+               mv88e6xxx_ppu_access_put(ds);
        }
 
        return ret;
@@ -380,7 +356,7 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
 
                if (!link) {
                        if (netif_carrier_ok(dev)) {
-                               printk(KERN_INFO "%s: link down\n", dev->name);
+                               netdev_info(dev, "link down\n");
                                netif_carrier_off(dev);
                        }
                        continue;
@@ -404,10 +380,11 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
                fc = (port_status & 0x8000) ? 1 : 0;
 
                if (!netif_carrier_ok(dev)) {
-                       printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
-                                        "flow control %sabled\n", dev->name,
-                                        speed, duplex ? "full" : "half",
-                                        fc ? "en" : "dis");
+                       netdev_info(dev,
+                                   "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+                                   speed,
+                                   duplex ? "full" : "half",
+                                   fc ? "en" : "dis");
                        netif_carrier_on(dev);
                }
        }
@@ -431,14 +408,10 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
 {
        int ret;
 
-       /*
-        * Snapshot the hardware statistics counters for this port.
-        */
+       /* Snapshot the hardware statistics counters for this port. */
        REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port);
 
-       /*
-        * Wait for the snapshotting to complete.
-        */
+       /* Wait for the snapshotting to complete. */
        ret = mv88e6xxx_stats_wait(ds);
        if (ret < 0)
                return ret;
@@ -502,9 +475,7 @@ void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
                return;
        }
 
-       /*
-        * Read each of the counters.
-        */
+       /* Read each of the counters. */
        for (i = 0; i < nr_stats; i++) {
                struct mv88e6xxx_hw_stat *s = stats + i;
                u32 low;
index fc2cd7b90e8d257f9144933bb93f29c77b51ad83..911ede58dd12d22223cfa71cce53e32eba55f5f8 100644 (file)
 #define REG_GLOBAL2            0x1c
 
 struct mv88e6xxx_priv_state {
-       /*
-        * When using multi-chip addressing, this mutex protects
+       /* When using multi-chip addressing, this mutex protects
         * access to the indirect access registers.  (In single-chip
         * mode, this mutex is effectively useless.)
         */
        struct mutex    smi_mutex;
 
 #ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
-       /*
-        * Handles automatic disabling and re-enabling of the PHY
+       /* Handles automatic disabling and re-enabling of the PHY
         * polling unit.
         */
        struct mutex            ppu_mutex;
@@ -34,8 +32,7 @@ struct mv88e6xxx_priv_state {
        struct timer_list       ppu_timer;
 #endif
 
-       /*
-        * This mutex serialises access to the statistics unit.
+       /* This mutex serialises access to the statistics unit.
         * Hold this mutex over snapshot + dump sequences.
         */
        struct mutex    stats_mutex;
@@ -52,7 +49,7 @@ struct mv88e6xxx_hw_stat {
 int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
 int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
 int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
-                          int reg, u16 val);
+                         int reg, u16 val);
 int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
 int mv88e6xxx_config_prio(struct dsa_switch *ds);
 int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
index c260af5411d0ff06685487b8781de707562f7e28..42aa54af684271d1a69ffd1852f1b2222bfbcd6d 100644 (file)
@@ -100,6 +100,15 @@ static void dummy_dev_uninit(struct net_device *dev)
        free_percpu(dev->dstats);
 }
 
+static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
+{
+       if (new_carrier)
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
+       return 0;
+}
+
 static const struct net_device_ops dummy_netdev_ops = {
        .ndo_init               = dummy_dev_init,
        .ndo_uninit             = dummy_dev_uninit,
@@ -108,6 +117,7 @@ static const struct net_device_ops dummy_netdev_ops = {
        .ndo_set_rx_mode        = set_multicast_list,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_get_stats64        = dummy_get_stats64,
+       .ndo_change_carrier     = dummy_change_carrier,
 };
 
 static void dummy_setup(struct net_device *dev)
diff --git a/drivers/net/ethernet/3com/3c501.c b/drivers/net/ethernet/3com/3c501.c
deleted file mode 100644 (file)
index 2038eaa..0000000
+++ /dev/null
@@ -1,896 +0,0 @@
-/* 3c501.c: A 3Com 3c501 Ethernet driver for Linux. */
-/*
-    Written 1992,1993,1994  Donald Becker
-
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU General Public License,
-    incorporated herein by reference.
-
-    This is a device driver for the 3Com Etherlink 3c501.
-    Do not purchase this card, even as a joke.  It's performance is horrible,
-    and it breaks in many ways.
-
-    The original author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-    Fixed (again!) the missing interrupt locking on TX/RX shifting.
-       Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Removed calls to init_etherdev since they are no longer needed, and
-    cleaned up modularization just a bit. The driver still allows only
-    the default address for cards when loaded as a module, but that's
-    really less braindead than anyone using a 3c501 board. :)
-                   19950208 (invid@msen.com)
-
-    Added traps for interrupts hitting the window as we clear and TX load
-    the board. Now getting 150K/second FTP with a 3c501 card. Still playing
-    with a TX-TX optimisation to see if we can touch 180-200K/second as seems
-    theoretically maximum.
-               19950402 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Cleaned up for 2.3.x because we broke SMP now.
-               20000208 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Check up pass for 2.5. Nothing significant changed
-               20021009 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Fixed zero fill corner case
-               20030104 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-
-   For the avoidance of doubt the "preferred form" of this code is one which
-   is in an open non patent encumbered format. Where cryptographic key signing
-   forms part of the process of creating an executable the information
-   including keys needed to generate an equivalently functional executable
-   are deemed to be part of the source code.
-
-*/
-
-
-/**
- * DOC: 3c501 Card Notes
- *
- *  Some notes on this thing if you have to hack it.  [Alan]
- *
- *  Some documentation is available from 3Com. Due to the boards age
- *  standard responses when you ask for this will range from 'be serious'
- *  to 'give it to a museum'. The documentation is incomplete and mostly
- *  of historical interest anyway.
- *
- *  The basic system is a single buffer which can be used to receive or
- *  transmit a packet. A third command mode exists when you are setting
- *  things up.
- *
- *  If it's transmitting it's not receiving and vice versa. In fact the
- *  time to get the board back into useful state after an operation is
- *  quite large.
- *
- *  The driver works by keeping the board in receive mode waiting for a
- *  packet to arrive. When one arrives it is copied out of the buffer
- *  and delivered to the kernel. The card is reloaded and off we go.
- *
- *  When transmitting lp->txing is set and the card is reset (from
- *  receive mode) [possibly losing a packet just received] to command
- *  mode. A packet is loaded and transmit mode triggered. The interrupt
- *  handler runs different code for transmit interrupts and can handle
- *  returning to receive mode or retransmissions (yes you have to help
- *  out with those too).
- *
- * DOC: Problems
- *
- *  There are a wide variety of undocumented error returns from the card
- *  and you basically have to kick the board and pray if they turn up. Most
- *  only occur under extreme load or if you do something the board doesn't
- *  like (eg touching a register at the wrong time).
- *
- *  The driver is less efficient than it could be. It switches through
- *  receive mode even if more transmits are queued. If this worries you buy
- *  a real Ethernet card.
- *
- *  The combination of slow receive restart and no real multicast
- *  filter makes the board unusable with a kernel compiled for IP
- *  multicasting in a real multicast environment. That's down to the board,
- *  but even with no multicast programs running a multicast IP kernel is
- *  in group 224.0.0.1 and you will therefore be listening to all multicasts.
- *  One nv conference running over that Ethernet and you can give up.
- *
- */
-
-#define DRV_NAME       "3c501"
-#define DRV_VERSION    "2002/10/09"
-
-
-static const char version[] =
-       DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n";
-
-/*
- *     Braindamage remaining:
- *     The 3c501 board.
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c501.h"
-
-/*
- *     The boilerplate probe code.
- */
-
-static int io = 0x280;
-static int irq = 5;
-static int mem_start;
-
-/**
- * el1_probe           -       probe for a 3c501
- * @dev: The device structure passed in to probe.
- *
- * This can be called from two places. The network layer will probe using
- * a device structure passed in with the probe information completed. For a
- * modular driver we use #init_module to fill in our own structure and probe
- * for it.
- *
- * Returns 0 on success. ENXIO if asked not to probe and ENODEV if asked to
- * probe and failing to find anything.
- */
-
-struct net_device * __init el1_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-       static const unsigned ports[] = { 0x280, 0x300, 0};
-       const unsigned *port;
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-               mem_start = dev->mem_start & 7;
-       }
-
-       if (io > 0x1ff) {       /* Check a single specified location. */
-               err = el1_probe1(dev, io);
-       } else if (io != 0) {
-               err = -ENXIO;           /* Don't probe at all. */
-       } else {
-               for (port = ports; *port && el1_probe1(dev, *port); port++)
-                       ;
-               if (!*port)
-                       err = -ENODEV;
-       }
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       release_region(dev->base_addr, EL1_IO_EXTENT);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops el_netdev_ops = {
-       .ndo_open               = el_open,
-       .ndo_stop               = el1_close,
-       .ndo_start_xmit         = el_start_xmit,
-       .ndo_tx_timeout         = el_timeout,
-       .ndo_set_rx_mode        = set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/**
- *     el1_probe1:
- *     @dev: The device structure to use
- *     @ioaddr: An I/O address to probe at.
- *
- *     The actual probe. This is iterated over by #el1_probe in order to
- *     check all the applicable device locations.
- *
- *     Returns 0 for a success, in which case the device is activated,
- *     EAGAIN if the IRQ is in use by another driver, and ENODEV if the
- *     board cannot be found.
- */
-
-static int __init el1_probe1(struct net_device *dev, int ioaddr)
-{
-       struct net_local *lp;
-       const char *mname;              /* Vendor name */
-       unsigned char station_addr[6];
-       int autoirq = 0;
-       int i;
-
-       /*
-        *      Reserve I/O resource for exclusive use by this driver
-        */
-
-       if (!request_region(ioaddr, EL1_IO_EXTENT, DRV_NAME))
-               return -ENODEV;
-
-       /*
-        *      Read the station address PROM data from the special port.
-        */
-
-       for (i = 0; i < 6; i++) {
-               outw(i, ioaddr + EL1_DATAPTR);
-               station_addr[i] = inb(ioaddr + EL1_SAPROM);
-       }
-       /*
-        *      Check the first three octets of the S.A. for 3Com's prefix, or
-        *      for the Sager NP943 prefix.
-        */
-
-       if (station_addr[0] == 0x02 && station_addr[1] == 0x60 &&
-           station_addr[2] == 0x8c)
-               mname = "3c501";
-       else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 &&
-                station_addr[2] == 0xC8)
-               mname = "NP943";
-       else {
-               release_region(ioaddr, EL1_IO_EXTENT);
-               return -ENODEV;
-       }
-
-       /*
-        *      We auto-IRQ by shutting off the interrupt line and letting it
-        *      float high.
-        */
-
-       dev->irq = irq;
-
-       if (dev->irq < 2) {
-               unsigned long irq_mask;
-
-               irq_mask = probe_irq_on();
-               inb(RX_STATUS);         /* Clear pending interrupts. */
-               inb(TX_STATUS);
-               outb(AX_LOOP + 1, AX_CMD);
-
-               outb(0x00, AX_CMD);
-
-               mdelay(20);
-               autoirq = probe_irq_off(irq_mask);
-
-               if (autoirq == 0) {
-                       pr_warning("%s probe at %#x failed to detect IRQ line.\n",
-                               mname, ioaddr);
-                       release_region(ioaddr, EL1_IO_EXTENT);
-                       return -EAGAIN;
-               }
-       }
-
-       outb(AX_RESET+AX_LOOP, AX_CMD);                 /* Loopback mode. */
-       dev->base_addr = ioaddr;
-       memcpy(dev->dev_addr, station_addr, ETH_ALEN);
-
-       if (mem_start & 0xf)
-               el_debug = mem_start & 0x7;
-       if (autoirq)
-               dev->irq = autoirq;
-
-       pr_info("%s: %s EtherLink at %#lx, using %sIRQ %d.\n",
-                       dev->name, mname, dev->base_addr,
-                       autoirq ? "auto":"assigned ", dev->irq);
-
-#ifdef CONFIG_IP_MULTICAST
-       pr_warning("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n");
-#endif
-
-       if (el_debug)
-               pr_debug("%s", version);
-
-       lp = netdev_priv(dev);
-       memset(lp, 0, sizeof(struct net_local));
-       spin_lock_init(&lp->lock);
-
-       /*
-        *      The EL1-specific entries in the device structure.
-        */
-
-       dev->netdev_ops = &el_netdev_ops;
-       dev->watchdog_timeo = HZ;
-       dev->ethtool_ops = &netdev_ethtool_ops;
-       return 0;
-}
-
-/**
- *     el1_open:
- *     @dev: device that is being opened
- *
- *     When an ifconfig is issued which changes the device flags to include
- *     IFF_UP this function is called. It is only called when the change
- *     occurs, not when the interface remains up. #el1_close will be called
- *     when it goes down.
- *
- *     Returns 0 for a successful open, or -EAGAIN if someone has run off
- *     with our interrupt line.
- */
-
-static int el_open(struct net_device *dev)
-{
-       int retval;
-       int ioaddr = dev->base_addr;
-       struct net_local *lp = netdev_priv(dev);
-       unsigned long flags;
-
-       if (el_debug > 2)
-               pr_debug("%s: Doing el_open()...\n", dev->name);
-
-       retval = request_irq(dev->irq, el_interrupt, 0, dev->name, dev);
-       if (retval)
-               return retval;
-
-       spin_lock_irqsave(&lp->lock, flags);
-       el_reset(dev);
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       lp->txing = 0;          /* Board in RX mode */
-       outb(AX_RX, AX_CMD);    /* Aux control, irq and receive enabled */
-       netif_start_queue(dev);
-       return 0;
-}
-
-/**
- * el_timeout:
- * @dev: The 3c501 card that has timed out
- *
- * Attempt to restart the board. This is basically a mixture of extreme
- * violence and prayer
- *
- */
-
-static void el_timeout(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       if (el_debug)
-               pr_debug("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
-                       dev->name, inb(TX_STATUS),
-                       inb(AX_STATUS), inb(RX_STATUS));
-       dev->stats.tx_errors++;
-       outb(TX_NORM, TX_CMD);
-       outb(RX_NORM, RX_CMD);
-       outb(AX_OFF, AX_CMD);   /* Just trigger a false interrupt. */
-       outb(AX_RX, AX_CMD);    /* Aux control, irq and receive enabled */
-       lp->txing = 0;          /* Ripped back in to RX */
-       netif_wake_queue(dev);
-}
-
-
-/**
- * el_start_xmit:
- * @skb: The packet that is queued to be sent
- * @dev: The 3c501 card we want to throw it down
- *
- * Attempt to send a packet to a 3c501 card. There are some interesting
- * catches here because the 3c501 is an extremely old and therefore
- * stupid piece of technology.
- *
- * If we are handling an interrupt on the other CPU we cannot load a packet
- * as we may still be attempting to retrieve the last RX packet buffer.
- *
- * When a transmit times out we dump the card into control mode and just
- * start again. It happens enough that it isn't worth logging.
- *
- * We avoid holding the spin locks when doing the packet load to the board.
- * The device is very slow, and its DMA mode is even slower. If we held the
- * lock while loading 1500 bytes onto the controller we would drop a lot of
- * serial port characters. This requires we do extra locking, but we have
- * no real choice.
- */
-
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned long flags;
-
-       /*
-        *      Avoid incoming interrupts between us flipping txing and flipping
-        *      mode as the driver assumes txing is a faithful indicator of card
-        *      state
-        */
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       /*
-        *      Avoid timer-based retransmission conflicts.
-        */
-
-       netif_stop_queue(dev);
-
-       do {
-               int len = skb->len;
-               int pad = 0;
-               int gp_start;
-               unsigned char *buf = skb->data;
-
-               if (len < ETH_ZLEN)
-                       pad = ETH_ZLEN - len;
-
-               gp_start = 0x800 - (len + pad);
-
-               lp->tx_pkt_start = gp_start;
-               lp->collisions = 0;
-
-               dev->stats.tx_bytes += skb->len;
-
-               /*
-                *      Command mode with status cleared should [in theory]
-                *      mean no more interrupts can be pending on the card.
-                */
-
-               outb_p(AX_SYS, AX_CMD);
-               inb_p(RX_STATUS);
-               inb_p(TX_STATUS);
-
-               lp->loading = 1;
-               lp->txing = 1;
-
-               /*
-                *      Turn interrupts back on while we spend a pleasant
-                *      afternoon loading bytes into the board
-                */
-
-               spin_unlock_irqrestore(&lp->lock, flags);
-
-               /* Set rx packet area to 0. */
-               outw(0x00, RX_BUF_CLR);
-               /* aim - packet will be loaded into buffer start */
-               outw(gp_start, GP_LOW);
-               /* load buffer (usual thing each byte increments the pointer) */
-               outsb(DATAPORT, buf, len);
-               if (pad) {
-                       while (pad--)           /* Zero fill buffer tail */
-                               outb(0, DATAPORT);
-               }
-               /* the board reuses the same register */
-               outw(gp_start, GP_LOW);
-
-               if (lp->loading != 2) {
-                       /* fire ... Trigger xmit.  */
-                       outb(AX_XMIT, AX_CMD);
-                       lp->loading = 0;
-                       if (el_debug > 2)
-                               pr_debug(" queued xmit.\n");
-                       dev_kfree_skb(skb);
-                       return NETDEV_TX_OK;
-               }
-               /* A receive upset our load, despite our best efforts */
-               if (el_debug > 2)
-                       pr_debug("%s: burped during tx load.\n", dev->name);
-               spin_lock_irqsave(&lp->lock, flags);
-       } while (1);
-}
-
-/**
- * el_interrupt:
- * @irq: Interrupt number
- * @dev_id: The 3c501 that burped
- *
- * Handle the ether interface interrupts. The 3c501 needs a lot more
- * hand holding than most cards. In particular we get a transmit interrupt
- * with a collision error because the board firmware isn't capable of rewinding
- * its own transmit buffer pointers. It can however count to 16 for us.
- *
- * On the receive side the card is also very dumb. It has no buffering to
- * speak of. We simply pull the packet out of its PIO buffer (which is slow)
- * and queue it for the kernel. Then we reset the card for the next packet.
- *
- * We sometimes get surprise interrupts late both because the SMP IRQ delivery
- * is message passing and because the card sometimes seems to deliver late. I
- * think if it is part way through a receive and the mode is changed it carries
- * on receiving and sends us an interrupt. We have to band aid all these cases
- * to get a sensible 150kBytes/second performance. Even then you want a small
- * TCP window.
- */
-
-static irqreturn_t el_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct net_local *lp;
-       int ioaddr;
-       int axsr;                       /* Aux. status reg. */
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-
-       spin_lock(&lp->lock);
-
-       /*
-        *      What happened ?
-        */
-
-       axsr = inb(AX_STATUS);
-
-       /*
-        *      Log it
-        */
-
-       if (el_debug > 3)
-               pr_debug("%s: el_interrupt() aux=%#02x\n", dev->name, axsr);
-
-       if (lp->loading == 1 && !lp->txing)
-               pr_warning("%s: Inconsistent state loading while not in tx\n",
-                       dev->name);
-
-       if (lp->txing) {
-               /*
-                *      Board in transmit mode. May be loading. If we are
-                *      loading we shouldn't have got this.
-                */
-               int txsr = inb(TX_STATUS);
-
-               if (lp->loading == 1) {
-                       if (el_debug > 2)
-                               pr_debug("%s: Interrupt while loading [txsr=%02x gp=%04x rp=%04x]\n",
-                                       dev->name, txsr, inw(GP_LOW), inw(RX_LOW));
-
-                       /* Force a reload */
-                       lp->loading = 2;
-                       spin_unlock(&lp->lock);
-                       goto out;
-               }
-               if (el_debug > 6)
-                       pr_debug("%s: txsr=%02x gp=%04x rp=%04x\n", dev->name,
-                                       txsr, inw(GP_LOW), inw(RX_LOW));
-
-               if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
-                       /*
-                        *      FIXME: is there a logic to whether to keep
-                        *      on trying or reset immediately ?
-                        */
-                       if (el_debug > 1)
-                               pr_debug("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n",
-                                       dev->name, txsr, axsr,
-                                       inw(ioaddr + EL1_DATAPTR),
-                                       inw(ioaddr + EL1_RXPTR));
-                       lp->txing = 0;
-                       netif_wake_queue(dev);
-               } else if (txsr & TX_16COLLISIONS) {
-                       /*
-                        *      Timed out
-                        */
-                       if (el_debug)
-                               pr_debug("%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name);
-                       outb(AX_SYS, AX_CMD);
-                       lp->txing = 0;
-                       dev->stats.tx_aborted_errors++;
-                       netif_wake_queue(dev);
-               } else if (txsr & TX_COLLISION) {
-                       /*
-                        *      Retrigger xmit.
-                        */
-
-                       if (el_debug > 6)
-                               pr_debug("%s: retransmitting after a collision.\n", dev->name);
-                       /*
-                        *      Poor little chip can't reset its own start
-                        *      pointer
-                        */
-
-                       outb(AX_SYS, AX_CMD);
-                       outw(lp->tx_pkt_start, GP_LOW);
-                       outb(AX_XMIT, AX_CMD);
-                       dev->stats.collisions++;
-                       spin_unlock(&lp->lock);
-                       goto out;
-               } else {
-                       /*
-                        *      It worked.. we will now fall through and receive
-                        */
-                       dev->stats.tx_packets++;
-                       if (el_debug > 6)
-                               pr_debug("%s: Tx succeeded %s\n", dev->name,
-                                       (txsr & TX_RDY) ? "." : "but tx is busy!");
-                       /*
-                        *      This is safe the interrupt is atomic WRT itself.
-                        */
-                       lp->txing = 0;
-                       /* In case more to transmit */
-                       netif_wake_queue(dev);
-               }
-       } else {
-               /*
-                *      In receive mode.
-                */
-
-               int rxsr = inb(RX_STATUS);
-               if (el_debug > 5)
-                       pr_debug("%s: rxsr=%02x txsr=%02x rp=%04x\n",
-                               dev->name, rxsr, inb(TX_STATUS), inw(RX_LOW));
-               /*
-                *      Just reading rx_status fixes most errors.
-                */
-               if (rxsr & RX_MISSED)
-                       dev->stats.rx_missed_errors++;
-               else if (rxsr & RX_RUNT) {
-                       /* Handled to avoid board lock-up. */
-                       dev->stats.rx_length_errors++;
-                       if (el_debug > 5)
-                               pr_debug("%s: runt.\n", dev->name);
-               } else if (rxsr & RX_GOOD) {
-                       /*
-                        *      Receive worked.
-                        */
-                       el_receive(dev);
-               } else {
-                       /*
-                        *      Nothing?  Something is broken!
-                        */
-                       if (el_debug > 2)
-                               pr_debug("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
-                                       dev->name, rxsr);
-                       el_reset(dev);
-               }
-       }
-
-       /*
-        *      Move into receive mode
-        */
-
-       outb(AX_RX, AX_CMD);
-       outw(0x00, RX_BUF_CLR);
-       inb(RX_STATUS);         /* Be certain that interrupts are cleared. */
-       inb(TX_STATUS);
-       spin_unlock(&lp->lock);
-out:
-       return IRQ_HANDLED;
-}
-
-
-/**
- * el_receive:
- * @dev: Device to pull the packets from
- *
- * We have a good packet. Well, not really "good", just mostly not broken.
- * We must check everything to see if it is good. In particular we occasionally
- * get wild packet sizes from the card. If the packet seems sane we PIO it
- * off the card and queue it for the protocol layers.
- */
-
-static void el_receive(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       int pkt_len;
-       struct sk_buff *skb;
-
-       pkt_len = inw(RX_LOW);
-
-       if (el_debug > 4)
-               pr_debug(" el_receive %d.\n", pkt_len);
-
-       if (pkt_len < 60 || pkt_len > 1536) {
-               if (el_debug)
-                       pr_debug("%s: bogus packet, length=%d\n",
-                                               dev->name, pkt_len);
-               dev->stats.rx_over_errors++;
-               return;
-       }
-
-       /*
-        *      Command mode so we can empty the buffer
-        */
-
-       outb(AX_SYS, AX_CMD);
-       skb = netdev_alloc_skb(dev, pkt_len + 2);
-
-       /*
-        *      Start of frame
-        */
-
-       outw(0x00, GP_LOW);
-       if (skb == NULL) {
-               pr_info("%s: Memory squeeze, dropping packet.\n", dev->name);
-               dev->stats.rx_dropped++;
-               return;
-       } else {
-               skb_reserve(skb, 2);    /* Force 16 byte alignment */
-               /*
-                *      The read increments through the bytes. The interrupt
-                *      handler will fix the pointer when it returns to
-                *      receive mode.
-                */
-               insb(DATAPORT, skb_put(skb, pkt_len), pkt_len);
-               skb->protocol = eth_type_trans(skb, dev);
-               netif_rx(skb);
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += pkt_len;
-       }
-}
-
-/**
- * el_reset: Reset a 3c501 card
- * @dev: The 3c501 card about to get zapped
- *
- * Even resetting a 3c501 isn't simple. When you activate reset it loses all
- * its configuration. You must hold the lock when doing this. The function
- * cannot take the lock itself as it is callable from the irq handler.
- */
-
-static void  el_reset(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       if (el_debug > 2)
-               pr_info("3c501 reset...\n");
-       outb(AX_RESET, AX_CMD);         /* Reset the chip */
-       /* Aux control, irq and loopback enabled */
-       outb(AX_LOOP, AX_CMD);
-       {
-               int i;
-               for (i = 0; i < 6; i++) /* Set the station address. */
-                       outb(dev->dev_addr[i], ioaddr + i);
-       }
-
-       outw(0, RX_BUF_CLR);            /* Set rx packet area to 0. */
-       outb(TX_NORM, TX_CMD);          /* tx irq on done, collision */
-       outb(RX_NORM, RX_CMD);          /* Set Rx commands. */
-       inb(RX_STATUS);                 /* Clear status. */
-       inb(TX_STATUS);
-       lp->txing = 0;
-}
-
-/**
- * el1_close:
- * @dev: 3c501 card to shut down
- *
- * Close a 3c501 card. The IFF_UP flag has been cleared by the user via
- * the SIOCSIFFLAGS ioctl. We stop any further transmissions being queued,
- * and then disable the interrupts. Finally we reset the chip. The effects
- * of the rest will be cleaned up by #el1_open. Always returns 0 indicating
- * a success.
- */
-
-static int el1_close(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       if (el_debug > 2)
-               pr_info("%s: Shutting down Ethernet card at %#x.\n",
-                                               dev->name, ioaddr);
-
-       netif_stop_queue(dev);
-
-       /*
-        *      Free and disable the IRQ.
-        */
-
-       free_irq(dev->irq, dev);
-       outb(AX_RESET, AX_CMD);         /* Reset the chip */
-
-       return 0;
-}
-
-/**
- * set_multicast_list:
- * @dev: The device to adjust
- *
- * Set or clear the multicast filter for this adaptor to use the best-effort
- * filtering supported. The 3c501 supports only three modes of filtering.
- * It always receives broadcasts and packets for itself. You can choose to
- * optionally receive all packets, or all multicast packets on top of this.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       if (dev->flags & IFF_PROMISC) {
-               outb(RX_PROM, RX_CMD);
-               inb(RX_STATUS);
-       } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
-               /* Multicast or all multicast is the same */
-               outb(RX_MULT, RX_CMD);
-               inb(RX_STATUS);         /* Clear status. */
-       } else {
-               outb(RX_NORM, RX_CMD);
-               inb(RX_STATUS);
-       }
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-       return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-       debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-       .get_msglevel           = netdev_get_msglevel,
-       .set_msglevel           = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-
-static struct net_device *dev_3c501;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink I/O base address");
-MODULE_PARM_DESC(irq, "EtherLink IRQ number");
-
-/**
- * init_module:
- *
- * When the driver is loaded as a module this function is called. We fake up
- * a device structure with the base I/O and interrupt set as if it were being
- * called from Space.c. This minimises the extra code that would otherwise
- * be required.
- *
- * Returns 0 for success or -EIO if a card is not found. Returning an error
- * here also causes the module to be unloaded
- */
-
-int __init init_module(void)
-{
-       dev_3c501 = el1_probe(-1);
-       if (IS_ERR(dev_3c501))
-               return PTR_ERR(dev_3c501);
-       return 0;
-}
-
-/**
- * cleanup_module:
- *
- * The module is being unloaded. We unhook our network device from the system
- * and then free up the resources we took when the card was found.
- */
-
-void __exit cleanup_module(void)
-{
-       struct net_device *dev = dev_3c501;
-       unregister_netdev(dev);
-       release_region(dev->base_addr, EL1_IO_EXTENT);
-       free_netdev(dev);
-}
-
-#endif /* MODULE */
-
-MODULE_AUTHOR("Donald Becker, Alan Cox");
-MODULE_DESCRIPTION("Support for the ancient 3Com 3c501 ethernet card");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/ethernet/3com/3c501.h b/drivers/net/ethernet/3com/3c501.h
deleted file mode 100644 (file)
index 183fd55..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-
-/*
- *     Index to functions.
- */
-
-static int  el1_probe1(struct net_device *dev, int ioaddr);
-static int  el_open(struct net_device *dev);
-static void el_timeout(struct net_device *dev);
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el_interrupt(int irq, void *dev_id);
-static void el_receive(struct net_device *dev);
-static void el_reset(struct net_device *dev);
-static int  el1_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-#define EL1_IO_EXTENT  16
-
-#ifndef EL_DEBUG
-#define EL_DEBUG  0    /* use 0 for production, 1 for devel., >2 for debug */
-#endif                 /* Anything above 5 is wordy death! */
-#define debug el_debug
-static int el_debug = EL_DEBUG;
-
-/*
- *     Board-specific info in netdev_priv(dev).
- */
-
-struct net_local
-{
-       int             tx_pkt_start;   /* The length of the current Tx packet. */
-       int             collisions;     /* Tx collisions this packet */
-       int             loading;        /* Spot buffer load collisions */
-       int             txing;          /* True if card is in TX mode */
-       spinlock_t      lock;           /* Serializing lock */
-};
-
-
-#define RX_STATUS (ioaddr + 0x06)
-#define RX_CMD   RX_STATUS
-#define TX_STATUS (ioaddr + 0x07)
-#define TX_CMD   TX_STATUS
-#define GP_LOW           (ioaddr + 0x08)
-#define GP_HIGH   (ioaddr + 0x09)
-#define RX_BUF_CLR (ioaddr + 0x0A)
-#define RX_LOW   (ioaddr + 0x0A)
-#define RX_HIGH   (ioaddr + 0x0B)
-#define SAPROM   (ioaddr + 0x0C)
-#define AX_STATUS (ioaddr + 0x0E)
-#define AX_CMD   AX_STATUS
-#define DATAPORT  (ioaddr + 0x0F)
-#define TX_RDY 0x08            /* In TX_STATUS */
-
-#define EL1_DATAPTR    0x08
-#define EL1_RXPTR      0x0A
-#define EL1_SAPROM     0x0C
-#define EL1_DATAPORT   0x0f
-
-/*
- *     Writes to the ax command register.
- */
-
-#define AX_OFF 0x00                    /* Irq off, buffer access on */
-#define AX_SYS  0x40                   /* Load the buffer */
-#define AX_XMIT 0x44                   /* Transmit a packet */
-#define AX_RX  0x48                    /* Receive a packet */
-#define AX_LOOP        0x0C                    /* Loopback mode */
-#define AX_RESET 0x80
-
-/*
- *     Normal receive mode written to RX_STATUS.  We must intr on short packets
- *     to avoid bogus rx lockups.
- */
-
-#define RX_NORM 0xA8           /* 0x68 == all addrs, 0xA8 only to me. */
-#define RX_PROM 0x68           /* Senior Prom, uhmm promiscuous mode. */
-#define RX_MULT 0xE8           /* Accept multicast packets. */
-#define TX_NORM 0x0A           /* Interrupt on everything that might hang the chip */
-
-/*
- *     TX_STATUS register.
- */
-
-#define TX_COLLISION 0x02
-#define TX_16COLLISIONS 0x04
-#define TX_READY 0x08
-
-#define RX_RUNT 0x08
-#define RX_MISSED 0x01         /* Missed a packet due to 3c501 braindamage. */
-#define RX_GOOD        0x30            /* Good packet 0x20, or simple overflow 0x10. */
-
index 633c709b9d996943c415cd0ad49e628a200eec34..f36ff99fd394e8491f4442a195b7fa18cff531ed 100644 (file)
@@ -1161,8 +1161,8 @@ el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
 
 static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int el3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index 59e1e001bc3f538d67f210a46646283890e8832b..94c656f5a05ddbe9a09e505009466961a8e119a2 100644 (file)
@@ -1542,9 +1542,10 @@ static void set_rx_mode(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info), "ISA 0x%lx",
+                dev->base_addr);
 }
 
 static u32 netdev_get_msglevel(struct net_device *dev)
index ed0feb3cc6fac83436a862b11e49d1fdbc07648c..1928e2001587405294acee6473139f7f86285f67 100644 (file)
@@ -1293,7 +1293,6 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
                pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
        for (i = 0; i < 3; i++)
                ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        if (print_info)
                pr_cont(" %pM", dev->dev_addr);
        /* Unfortunately an all zero eeprom passes the checksum and this
index eb56174469a7f9d90f96f8f8dc2858b0b0c4addb..1c71c763f68009906a1d0bb1cd3eaf636a43ba1f 100644 (file)
@@ -5,7 +5,7 @@
 config NET_VENDOR_3COM
        bool "3Com devices"
        default y
-       depends on ISA || EISA || MCA || PCI || PCMCIA
+       depends on ISA || EISA || PCI || PCMCIA
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
          and read the Ethernet-HOWTO, available from
@@ -18,23 +18,9 @@ config NET_VENDOR_3COM
 
 if NET_VENDOR_3COM
 
-config EL1
-       tristate "3c501 \"EtherLink\" support"
-       depends on ISA
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.  Also, consider buying a
-         new card, since the 3c501 is slow, broken, and obsolete: you will
-         have problems.  Some people suggest to ping ("man ping") a nearby
-         machine every minute ("man cron") when using this card.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c501.
-
 config EL3
-       tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
-       depends on (ISA || EISA || MCA)
+       tristate "3c509/3c579 \"EtherLink III\" support"
+       depends on (ISA || EISA)
        ---help---
          If you have a network (Ethernet) card belonging to the 3Com
          EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
index 1e5382a30eadfe7eb9194a64bf2401177d0ea62a..74046afab99319b3784a8c1afd3dbe6397ae1724 100644 (file)
@@ -2,7 +2,6 @@
 # Makefile for the 3Com Ethernet device drivers
 #
 
-obj-$(CONFIG_EL1) += 3c501.o
 obj-$(CONFIG_EL3) += 3c509.o
 obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
diff --git a/drivers/net/ethernet/8390/3c503.c b/drivers/net/ethernet/8390/3c503.c
deleted file mode 100644 (file)
index 49d76bd..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-/* 3c503.c: A shared-memory NS8390 ethernet driver for linux. */
-/*
-    Written 1992-94 by Donald Becker.
-
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU General Public License,
-    incorporated herein by reference.
-
-    The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-
-    This driver should work with the 3c503 and 3c503/16.  It should be used
-    in shared memory mode for best performance, although it may also work
-    in programmed-I/O mode.
-
-    Sources:
-    EtherLink II Technical Reference Manual,
-    EtherLink II/16 Technical Reference Manual Supplement,
-    3Com Corporation, 5400 Bayfront Plaza, Santa Clara CA 95052-8145
-
-    The Crynwr 3c503 packet driver.
-
-    Changelog:
-
-    Paul Gortmaker     : add support for the 2nd 8kB of RAM on 16 bit cards.
-    Paul Gortmaker     : multiple card support for module users.
-    rjohnson@analogic.com : Fix up PIO interface for efficient operation.
-    Jeff Garzik                : ethtool support
-
-*/
-
-#define DRV_NAME       "3c503"
-#define DRV_VERSION    "1.10a"
-#define DRV_RELDATE    "11/17/2001"
-
-
-static const char version[] =
-    DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Donald Becker (becker@scyld.com)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ethtool.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
-#include "8390.h"
-#include "3c503.h"
-#define WRD_COUNT 4
-
-static int el2_pio_probe(struct net_device *dev);
-static int el2_probe1(struct net_device *dev, int ioaddr);
-
-/* A zero-terminated list of I/O addresses to be probed in PIO mode. */
-static unsigned int netcard_portlist[] __initdata =
-       { 0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
-
-#define EL2_IO_EXTENT  16
-
-static int el2_open(struct net_device *dev);
-static int el2_close(struct net_device *dev);
-static void el2_reset_8390(struct net_device *dev);
-static void el2_init_card(struct net_device *dev);
-static void el2_block_output(struct net_device *dev, int count,
-                            const unsigned char *buf, int start_page);
-static void el2_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-                          int ring_offset);
-static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                        int ring_page);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-
-/* This routine probes for a memory-mapped 3c503 board by looking for
-   the "location register" at the end of the jumpered boot PROM space.
-   This works even if a PROM isn't there.
-
-   If the ethercard isn't found there is an optional probe for
-   ethercard jumpered to programmed-I/O mode.
-   */
-static int __init do_el2_probe(struct net_device *dev)
-{
-    int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
-    int base_addr = dev->base_addr;
-    int irq = dev->irq;
-
-    if (base_addr > 0x1ff)     /* Check a single specified location. */
-       return el2_probe1(dev, base_addr);
-    else if (base_addr != 0)           /* Don't probe at all. */
-       return -ENXIO;
-
-    for (addr = addrs; *addr; addr++) {
-       void __iomem *p = ioremap(*addr, 1);
-       unsigned base_bits;
-       int i;
-
-       if (!p)
-               continue;
-       base_bits = readb(p);
-       iounmap(p);
-       i = ffs(base_bits) - 1;
-       if (i == -1 || base_bits != (1 << i))
-           continue;
-       if (el2_probe1(dev, netcard_portlist[i]) == 0)
-           return 0;
-       dev->irq = irq;
-    }
-#if ! defined(no_probe_nonshared_memory)
-    return el2_pio_probe(dev);
-#else
-    return -ENODEV;
-#endif
-}
-
-/*  Try all of the locations that aren't obviously empty.  This touches
-    a lot of locations, and is much riskier than the code above. */
-static int __init
-el2_pio_probe(struct net_device *dev)
-{
-    int i;
-    int base_addr = dev->base_addr;
-    int irq = dev->irq;
-
-    if (base_addr > 0x1ff)     /* Check a single specified location. */
-       return el2_probe1(dev, base_addr);
-    else if (base_addr != 0)   /* Don't probe at all. */
-       return -ENXIO;
-
-    for (i = 0; netcard_portlist[i]; i++) {
-       if (el2_probe1(dev, netcard_portlist[i]) == 0)
-           return 0;
-       dev->irq = irq;
-    }
-
-    return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init el2_probe(int unit)
-{
-       struct net_device *dev = alloc_eip_netdev();
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_el2_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops el2_netdev_ops = {
-       .ndo_open               = el2_open,
-       .ndo_stop               = el2_close,
-
-       .ndo_start_xmit         = eip_start_xmit,
-       .ndo_tx_timeout         = eip_tx_timeout,
-       .ndo_get_stats          = eip_get_stats,
-       .ndo_set_rx_mode        = eip_set_multicast_list,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = eip_poll,
-#endif
-};
-
-/* Probe for the Etherlink II card at I/O port base IOADDR,
-   returning non-zero on success.  If found, set the station
-   address and memory parameters in DEVICE. */
-static int __init
-el2_probe1(struct net_device *dev, int ioaddr)
-{
-    int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
-    static unsigned version_printed;
-    unsigned long vendor_id;
-
-    if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
-       return -EBUSY;
-
-    if (!request_region(ioaddr + 0x400, 8, DRV_NAME)) {
-       retval = -EBUSY;
-       goto out;
-    }
-
-    /* Reset and/or avoid any lurking NE2000 */
-    if (inb(ioaddr + 0x408) == 0xff) {
-       mdelay(1);
-       retval = -ENODEV;
-       goto out1;
-    }
-
-    /* We verify that it's a 3C503 board by checking the first three octets
-       of its ethernet address. */
-    iobase_reg = inb(ioaddr+0x403);
-    membase_reg = inb(ioaddr+0x404);
-    /* ASIC location registers should be 0 or have only a single bit set. */
-    if ((iobase_reg  & (iobase_reg - 1)) ||
-       (membase_reg & (membase_reg - 1))) {
-       retval = -ENODEV;
-       goto out1;
-    }
-    saved_406 = inb_p(ioaddr + 0x406);
-    outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
-    outb_p(ECNTRL_THIN, ioaddr + 0x406);
-    /* Map the station addr PROM into the lower I/O ports. We now check
-       for both the old and new 3Com prefix */
-    outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
-    vendor_id = inb(ioaddr)*0x10000 + inb(ioaddr + 1)*0x100 + inb(ioaddr + 2);
-    if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) {
-       /* Restore the register we frobbed. */
-       outb(saved_406, ioaddr + 0x406);
-       retval = -ENODEV;
-       goto out1;
-    }
-
-    if (ei_debug  &&  version_printed++ == 0)
-       pr_debug("%s", version);
-
-    dev->base_addr = ioaddr;
-
-    pr_info("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr);
-
-    /* Retrieve and print the ethernet address. */
-    for (i = 0; i < 6; i++)
-       dev->dev_addr[i] = inb(ioaddr + i);
-    pr_cont("%pM", dev->dev_addr);
-
-    /* Map the 8390 back into the window. */
-    outb(ECNTRL_THIN, ioaddr + 0x406);
-
-    /* Check for EL2/16 as described in tech. man. */
-    outb_p(E8390_PAGE0, ioaddr + E8390_CMD);
-    outb_p(0, ioaddr + EN0_DCFG);
-    outb_p(E8390_PAGE2, ioaddr + E8390_CMD);
-    wordlength = inb_p(ioaddr + EN0_DCFG) & ENDCFG_WTS;
-    outb_p(E8390_PAGE0, ioaddr + E8390_CMD);
-
-    /* Probe for, turn on and clear the board's shared memory. */
-    if (ei_debug > 2)
-       pr_cont(" memory jumpers %2.2x ", membase_reg);
-    outb(EGACFR_NORM, ioaddr + 0x405); /* Enable RAM */
-
-    /* This should be probed for (or set via an ioctl()) at run-time.
-       Right now we use a sleazy hack to pass in the interface number
-       at boot-time via the low bits of the mem_end field.  That value is
-       unused, and the low bits would be discarded even if it was used. */
-#if defined(EI8390_THICK) || defined(EL2_AUI)
-    ei_status.interface_num = 1;
-#else
-    ei_status.interface_num = dev->mem_end & 0xf;
-#endif
-    pr_cont(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex");
-
-    if ((membase_reg & 0xf0) == 0) {
-       dev->mem_start = 0;
-       ei_status.name = "3c503-PIO";
-       ei_status.mem = NULL;
-    } else {
-       dev->mem_start = ((membase_reg & 0xc0) ? 0xD8000 : 0xC8000) +
-           ((membase_reg & 0xA0) ? 0x4000 : 0);
-#define EL2_MEMSIZE (EL2_MB1_STOP_PG - EL2_MB1_START_PG)*256
-       ei_status.mem = ioremap(dev->mem_start, EL2_MEMSIZE);
-
-#ifdef EL2MEMTEST
-       /* This has never found an error, but someone might care.
-          Note that it only tests the 2nd 8kB on 16kB 3c503/16
-          cards between card addr. 0x2000 and 0x3fff. */
-       {                       /* Check the card's memory. */
-           void __iomem *mem_base = ei_status.mem;
-           unsigned int test_val = 0xbbadf00d;
-           writel(0xba5eba5e, mem_base);
-           for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) {
-               writel(test_val, mem_base + i);
-               if (readl(mem_base) != 0xba5eba5e ||
-                   readl(mem_base + i) != test_val) {
-                   pr_warning("3c503: memory failure or memory address conflict.\n");
-                   dev->mem_start = 0;
-                   ei_status.name = "3c503-PIO";
-                   iounmap(mem_base);
-                   ei_status.mem = NULL;
-                   break;
-               }
-               test_val += 0x55555555;
-               writel(0, mem_base + i);
-           }
-       }
-#endif  /* EL2MEMTEST */
-
-       if (dev->mem_start)
-               dev->mem_end = dev->mem_start + EL2_MEMSIZE;
-
-       if (wordlength) {       /* No Tx pages to skip over to get to Rx */
-               ei_status.priv = 0;
-               ei_status.name = "3c503/16";
-       } else {
-               ei_status.priv = TX_PAGES * 256;
-               ei_status.name = "3c503";
-       }
-    }
-
-    /*
-       Divide up the memory on the card. This is the same regardless of
-       whether shared-mem or PIO is used. For 16 bit cards (16kB RAM),
-       we use the entire 8k of bank1 for an Rx ring. We only use 3k
-       of the bank0 for 2 full size Tx packet slots. For 8 bit cards,
-       (8kB RAM) we use 3kB of bank1 for two Tx slots, and the remaining
-       5kB for an Rx ring.  */
-
-    if (wordlength) {
-       ei_status.tx_start_page = EL2_MB0_START_PG;
-       ei_status.rx_start_page = EL2_MB1_START_PG;
-    } else {
-       ei_status.tx_start_page = EL2_MB1_START_PG;
-       ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES;
-    }
-
-    /* Finish setting the board's parameters. */
-    ei_status.stop_page = EL2_MB1_STOP_PG;
-    ei_status.word16 = wordlength;
-    ei_status.reset_8390 = el2_reset_8390;
-    ei_status.get_8390_hdr = el2_get_8390_hdr;
-    ei_status.block_input = el2_block_input;
-    ei_status.block_output = el2_block_output;
-
-    if (dev->irq == 2)
-       dev->irq = 9;
-    else if (dev->irq > 5 && dev->irq != 9) {
-       pr_warning("3c503: configured interrupt %d invalid, will use autoIRQ.\n",
-              dev->irq);
-       dev->irq = 0;
-    }
-
-    ei_status.saved_irq = dev->irq;
-
-    dev->netdev_ops = &el2_netdev_ops;
-    dev->ethtool_ops = &netdev_ethtool_ops;
-
-    retval = register_netdev(dev);
-    if (retval)
-       goto out1;
-
-    if (dev->mem_start)
-       pr_info("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
-               dev->name, ei_status.name, (wordlength+1)<<3,
-               dev->mem_start, dev->mem_end-1);
-
-    else
-    {
-       ei_status.tx_start_page = EL2_MB1_START_PG;
-       ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES;
-       pr_info("%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n",
-              dev->name, ei_status.name, (wordlength+1)<<3);
-    }
-    release_region(ioaddr + 0x400, 8);
-    return 0;
-out1:
-    release_region(ioaddr + 0x400, 8);
-out:
-    release_region(ioaddr, EL2_IO_EXTENT);
-    return retval;
-}
-
-static irqreturn_t el2_probe_interrupt(int irq, void *seen)
-{
-       *(bool *)seen = true;
-       return IRQ_HANDLED;
-}
-
-static int
-el2_open(struct net_device *dev)
-{
-    int retval;
-
-    if (dev->irq < 2) {
-       static const int irqlist[] = {5, 9, 3, 4, 0};
-       const int *irqp = irqlist;
-
-       outb(EGACFR_NORM, E33G_GACFR);  /* Enable RAM and interrupts. */
-       do {
-               bool seen;
-
-               retval = request_irq(*irqp, el2_probe_interrupt, 0,
-                                    dev->name, &seen);
-               if (retval == -EBUSY)
-                       continue;
-               if (retval < 0)
-                       goto err_disable;
-
-               /* Twinkle the interrupt, and check if it's seen. */
-               seen = false;
-               smp_wmb();
-               outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
-               outb_p(0x00, E33G_IDCFR);
-               msleep(1);
-               free_irq(*irqp, &seen);
-               if (!seen)
-                       continue;
-
-               retval = request_irq(dev->irq = *irqp, eip_interrupt, 0,
-                                    dev->name, dev);
-               if (retval == -EBUSY)
-                       continue;
-               if (retval < 0)
-                       goto err_disable;
-               break;
-       } while (*++irqp);
-
-       if (*irqp == 0) {
-       err_disable:
-           outb(EGACFR_IRQOFF, E33G_GACFR);    /* disable interrupts. */
-           return -EAGAIN;
-       }
-    } else {
-       if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
-           return retval;
-       }
-    }
-
-    el2_init_card(dev);
-    eip_open(dev);
-    return 0;
-}
-
-static int
-el2_close(struct net_device *dev)
-{
-    free_irq(dev->irq, dev);
-    dev->irq = ei_status.saved_irq;
-    outb(EGACFR_IRQOFF, E33G_GACFR);   /* disable interrupts. */
-
-    eip_close(dev);
-    return 0;
-}
-
-/* This is called whenever we have a unrecoverable failure:
-       transmit timeout
-       Bad ring buffer packet header
- */
-static void
-el2_reset_8390(struct net_device *dev)
-{
-    if (ei_debug > 1) {
-       pr_debug("%s: Resetting the 3c503 board...", dev->name);
-       pr_cont(" %#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR),
-              E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR));
-    }
-    outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL);
-    ei_status.txing = 0;
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-    el2_init_card(dev);
-    if (ei_debug > 1)
-       pr_cont("done\n");
-}
-
-/* Initialize the 3c503 GA registers after a reset. */
-static void
-el2_init_card(struct net_device *dev)
-{
-    /* Unmap the station PROM and select the DIX or BNC connector. */
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-
-    /* Set ASIC copy of rx's first and last+1 buffer pages */
-    /* These must be the same as in the 8390. */
-    outb(ei_status.rx_start_page, E33G_STARTPG);
-    outb(ei_status.stop_page,  E33G_STOPPG);
-
-    /* Point the vector pointer registers somewhere ?harmless?. */
-    outb(0xff, E33G_VP2);      /* Point at the ROM restart location 0xffff0 */
-    outb(0xff, E33G_VP1);
-    outb(0x00, E33G_VP0);
-    /* Turn off all interrupts until we're opened. */
-    outb_p(0x00,  dev->base_addr + EN0_IMR);
-    /* Enable IRQs iff started. */
-    outb(EGACFR_NORM, E33G_GACFR);
-
-    /* Set the interrupt line. */
-    outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
-    outb_p((WRD_COUNT << 1), E33G_DRQCNT);     /* Set burst size to 8 */
-    outb_p(0x20, E33G_DMAAH);  /* Put a valid addr in the GA DMA */
-    outb_p(0x00, E33G_DMAAL);
-    return;                    /* We always succeed */
-}
-
-/*
- * Either use the shared memory (if enabled on the board) or put the packet
- * out through the ASIC FIFO.
- */
-static void
-el2_block_output(struct net_device *dev, int count,
-                const unsigned char *buf, int start_page)
-{
-    unsigned short int *wrd;
-    int boguscount;            /* timeout counter */
-    unsigned short word;       /* temporary for better machine code */
-    void __iomem *base = ei_status.mem;
-
-    if (ei_status.word16)      /* Tx packets go into bank 0 on EL2/16 card */
-       outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR);
-    else
-       outb(EGACFR_NORM, E33G_GACFR);
-
-    if (base) {        /* Shared memory transfer */
-       memcpy_toio(base + ((start_page - ei_status.tx_start_page) << 8),
-                       buf, count);
-       outb(EGACFR_NORM, E33G_GACFR);  /* Back to bank1 in case on bank0 */
-       return;
-    }
-
-/*
- *  No shared memory, put the packet out the other way.
- *  Set up then start the internal memory transfer to Tx Start Page
- */
-
-    word = (unsigned short)start_page;
-    outb(word&0xFF, E33G_DMAAH);
-    outb(word>>8, E33G_DMAAL);
-
-    outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT
-          | ECNTRL_START, E33G_CNTRL);
-
-/*
- *  Here I am going to write data to the FIFO as quickly as possible.
- *  Note that E33G_FIFOH is defined incorrectly. It is really
- *  E33G_FIFOL, the lowest port address for both the byte and
- *  word write. Variable 'count' is NOT checked. Caller must supply a
- *  valid count. Note that I may write a harmless extra byte to the
- *  8390 if the byte-count was not even.
- */
-    wrd = (unsigned short int *) buf;
-    count  = (count + 1) >> 1;
-    for(;;)
-    {
-        boguscount = 0x1000;
-        while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-        {
-            if(!boguscount--)
-            {
-                pr_notice("%s: FIFO blocked in el2_block_output.\n", dev->name);
-                el2_reset_8390(dev);
-                goto blocked;
-            }
-        }
-        if(count > WRD_COUNT)
-        {
-            outsw(E33G_FIFOH, wrd, WRD_COUNT);
-            wrd   += WRD_COUNT;
-            count -= WRD_COUNT;
-        }
-        else
-        {
-            outsw(E33G_FIFOH, wrd, count);
-            break;
-        }
-    }
-    blocked:;
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-/* Read the 4 byte, page aligned 8390 specific header. */
-static void
-el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-    int boguscount;
-    void __iomem *base = ei_status.mem;
-    unsigned short word;
-
-    if (base) {       /* Use the shared memory. */
-       void __iomem *hdr_start = base + ((ring_page - EL2_MB1_START_PG)<<8);
-       memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-       hdr->count = le16_to_cpu(hdr->count);
-       return;
-    }
-
-/*
- *  No shared memory, use programmed I/O.
- */
-
-    word = (unsigned short)ring_page;
-    outb(word&0xFF, E33G_DMAAH);
-    outb(word>>8, E33G_DMAAL);
-
-    outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
-          | ECNTRL_START, E33G_CNTRL);
-    boguscount = 0x1000;
-    while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-    {
-        if(!boguscount--)
-        {
-            pr_notice("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name);
-            memset(hdr, 0x00, sizeof(struct e8390_pkt_hdr));
-            el2_reset_8390(dev);
-            goto blocked;
-        }
-    }
-    insw(E33G_FIFOH, hdr, (sizeof(struct e8390_pkt_hdr))>> 1);
-    blocked:;
-    outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-
-static void
-el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-    int boguscount = 0;
-    void __iomem *base = ei_status.mem;
-    unsigned short int *buf;
-    unsigned short word;
-
-    /* Maybe enable shared memory just be to be safe... nahh.*/
-    if (base) {        /* Use the shared memory. */
-       ring_offset -= (EL2_MB1_START_PG<<8);
-       if (ring_offset + count > EL2_MEMSIZE) {
-           /* We must wrap the input move. */
-           int semi_count = EL2_MEMSIZE - ring_offset;
-           memcpy_fromio(skb->data, base + ring_offset, semi_count);
-           count -= semi_count;
-           memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
-       } else {
-               memcpy_fromio(skb->data, base + ring_offset, count);
-       }
-       return;
-    }
-
-/*
- *  No shared memory, use programmed I/O.
- */
-    word = (unsigned short) ring_offset;
-    outb(word>>8, E33G_DMAAH);
-    outb(word&0xFF, E33G_DMAAL);
-
-    outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
-          | ECNTRL_START, E33G_CNTRL);
-
-/*
- *  Here I also try to get data as fast as possible. I am betting that I
- *  can read one extra byte without clobbering anything in the kernel because
- *  this would only occur on an odd byte-count and allocation of skb->data
- *  is word-aligned. Variable 'count' is NOT checked. Caller must check
- *  for a valid count.
- *  [This is currently quite safe.... but if one day the 3c503 explodes
- *   you know where to come looking ;)]
- */
-
-    buf =  (unsigned short int *) skb->data;
-    count =  (count + 1) >> 1;
-    for(;;)
-    {
-        boguscount = 0x1000;
-        while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-        {
-            if(!boguscount--)
-            {
-                pr_notice("%s: FIFO blocked in el2_block_input.\n", dev->name);
-                el2_reset_8390(dev);
-                goto blocked;
-            }
-        }
-        if(count > WRD_COUNT)
-        {
-            insw(E33G_FIFOH, buf, WRD_COUNT);
-            buf   += WRD_COUNT;
-            count -= WRD_COUNT;
-        }
-        else
-        {
-            insw(E33G_FIFOH, buf, count);
-            break;
-        }
-    }
-    blocked:;
-    outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-};
-
-#ifdef MODULE
-#define MAX_EL2_CARDS  4       /* Max number of EL2 cards per module */
-
-static struct net_device *dev_el2[MAX_EL2_CARDS];
-static int io[MAX_EL2_CARDS];
-static int irq[MAX_EL2_CARDS];
-static int xcvr[MAX_EL2_CARDS];        /* choose int. or ext. xcvr */
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(xcvr, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(xcvr, "transceiver(s) (0=internal, 1=external)");
-MODULE_DESCRIPTION("3Com ISA EtherLink II, II/16 (3c503, 3c503/16) driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
-               if (io[this_dev] == 0)  {
-                       if (this_dev != 0) break; /* only autoprobe 1st one */
-                       pr_notice("3c503.c: Presently autoprobing (not recommended) for a single card.\n");
-               }
-               dev = alloc_eip_netdev();
-               if (!dev)
-                       break;
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               dev->mem_end = xcvr[this_dev];  /* low 4bits = xcvr sel. */
-               if (do_el2_probe(dev) == 0) {
-                       dev_el2[found++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               pr_warning("3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-       /* NB: el2_close() handles free_irq */
-       release_region(dev->base_addr, EL2_IO_EXTENT);
-       if (ei_status.mem)
-               iounmap(ei_status.mem);
-}
-
-void __exit
-cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
-               struct net_device *dev = dev_el2[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/3c503.h b/drivers/net/ethernet/8390/3c503.h
deleted file mode 100644 (file)
index e2367b8..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Definitions for the 3Com 3c503 Etherlink 2. */
-/* This file is distributed under the GPL.
-   Many of these names and comments are directly from the Crynwr packet
-   drivers, which are released under the GPL. */
-
-#define EL2H (dev->base_addr + 0x400)
-#define EL2L (dev->base_addr)
-
-/* Vendor unique hardware addr. prefix. 3Com has 2 because they ran
-   out of available addresses on the first one... */
-
-#define OLD_3COM_ID    0x02608c
-#define NEW_3COM_ID    0x0020af
-
-/* Shared memory management parameters. NB: The 8 bit cards have only
-   one bank (MB1) which serves both Tx and Rx packet space. The 16bit
-   cards have 2 banks, MB0 for Tx packets, and MB1 for Rx packets.
-   You choose which bank appears in the sh. mem window with EGACFR_MBSn */
-
-#define EL2_MB0_START_PG       (0x00)  /* EL2/16 Tx packets go in bank 0 */
-#define EL2_MB1_START_PG       (0x20)  /* First page of bank 1 */
-#define EL2_MB1_STOP_PG                (0x40)  /* Last page +1 of bank 1 */
-
-/* 3Com 3c503 ASIC registers */
-#define E33G_STARTPG   (EL2H+0)        /* Start page, matching EN0_STARTPG */
-#define E33G_STOPPG    (EL2H+1)        /* Stop page, must match EN0_STOPPG */
-#define E33G_DRQCNT    (EL2H+2)        /* DMA burst count */
-#define E33G_IOBASE    (EL2H+3)        /* Read of I/O base jumpers. */
-       /* (non-useful, but it also appears at the end of EPROM space) */
-#define E33G_ROMBASE   (EL2H+4)        /* Read of memory base jumpers. */
-#define E33G_GACFR     (EL2H+5)        /* Config/setup bits for the ASIC GA */
-#define E33G_CNTRL     (EL2H+6)        /* Board's main control register */
-#define E33G_STATUS    (EL2H+7)        /* Status on completions. */
-#define E33G_IDCFR     (EL2H+8)        /* Interrupt/DMA config register */
-                               /* (Which IRQ to assert, DMA chan to use) */
-#define E33G_DMAAH     (EL2H+9)        /* High byte of DMA address reg */
-#define E33G_DMAAL     (EL2H+10)       /* Low byte of DMA address reg */
-/* "Vector pointer" - if this address matches a read, the EPROM (rather than
-   shared RAM) is mapped into memory space. */
-#define E33G_VP2       (EL2H+11)
-#define E33G_VP1       (EL2H+12)
-#define E33G_VP0       (EL2H+13)
-#define E33G_FIFOH     (EL2H+14)       /* FIFO for programmed I/O moves */
-#define E33G_FIFOL     (EL2H+15)       /* ... low byte of above. */
-
-/* Bits in E33G_CNTRL register: */
-
-#define ECNTRL_RESET   (0x01)  /* Software reset of the ASIC and 8390 */
-#define ECNTRL_THIN    (0x02)  /* Onboard xcvr enable, AUI disable */
-#define ECNTRL_AUI     (0x00)  /* Onboard xcvr disable, AUI enable */
-#define ECNTRL_SAPROM  (0x04)  /* Map the station address prom */
-#define ECNTRL_DBLBFR  (0x20)  /* FIFO configuration bit */
-#define ECNTRL_OUTPUT  (0x40)  /* PC-to-3C503 direction if 1 */
-#define ECNTRL_INPUT   (0x00)  /* 3C503-to-PC direction if 0 */
-#define ECNTRL_START   (0x80)  /* Start the DMA logic */
-
-/* Bits in E33G_STATUS register: */
-
-#define ESTAT_DPRDY    (0x80)  /* Data port (of FIFO) ready */
-#define ESTAT_UFLW     (0x40)  /* Tried to read FIFO when it was empty */
-#define ESTAT_OFLW     (0x20)  /* Tried to write FIFO when it was full */
-#define ESTAT_DTC      (0x10)  /* Terminal Count from PC bus DMA logic */
-#define ESTAT_DIP      (0x08)  /* DMA In Progress */
-
-/* Bits in E33G_GACFR register: */
-
-#define EGACFR_NIM     (0x80)  /* NIC interrupt mask */
-#define EGACFR_TCM     (0x40)  /* DMA term. count interrupt mask */
-#define EGACFR_RSEL    (0x08)  /* Map a bank of card mem into system mem */
-#define EGACFR_MBS2    (0x04)  /* Memory bank select, bit 2. */
-#define EGACFR_MBS1    (0x02)  /* Memory bank select, bit 1. */
-#define EGACFR_MBS0    (0x01)  /* Memory bank select, bit 0. */
-
-#define EGACFR_NORM    (0x49)  /* TCM | RSEL | MBS0 */
-#define EGACFR_IRQOFF  (0xc9)  /* TCM | RSEL | MBS0 | NIM */
-
-/*
-       MBS2    MBS1    MBS0    Sh. mem windows card mem at:
-       ----    ----    ----    -----------------------------
-       0       0       0       0x0000 -- bank 0
-       0       0       1       0x2000 -- bank 1 (only choice for 8bit card)
-       0       1       0       0x4000 -- bank 2, not used
-       0       1       1       0x6000 -- bank 3, not used
-
-There was going to be a 32k card that used bank 2 and 3, but it
-never got produced.
-
-*/
-
-
-/* End of 3C503 parameter definitions */
index e1219e037c04de3bd3fb9a7ec39e324b3e8d83c9..1b78ca7a97868d78728bee1d25fc72203d1bfb28 100644 (file)
@@ -6,8 +6,8 @@ config NET_VENDOR_8390
        bool "National Semi-conductor 8390 devices"
        default y
        depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \
-                  ISA || MCA || EISA || MAC || M32R || MACH_TX49XX || \
-                  MCA_LEGACY || H8300 || ARM || MIPS || ZORRO || PCMCIA || \
+                  ISA || MAC || M32R || MACH_TX49XX || \
+                  H8300 || ARM || MIPS || ZORRO || PCMCIA || \
                   EXPERIMENTAL)
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
@@ -21,30 +21,6 @@ config NET_VENDOR_8390
 
 if NET_VENDOR_8390
 
-config EL2
-       tristate "3c503 \"EtherLink II\" support"
-       depends on ISA
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c503.
-
-config AC3200
-       tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
-       depends on PCI && (ISA || EISA) && EXPERIMENTAL
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called ac3200.
-
 config PCMCIA_AXNET
        tristate "Asix AX88190 PCMCIA support"
        depends on PCMCIA
@@ -74,54 +50,6 @@ config AX88796_93CX6
        ---help---
          Select this if your platform comes with an external 93CX6 eeprom.
 
-config E2100
-       tristate "Cabletron E21xx support"
-       depends on ISA
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called e2100.
-
-config ES3210
-       tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
-       depends on PCI && EISA && EXPERIMENTAL
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called es3210.
-
-config HPLAN_PLUS
-       tristate "HP PCLAN+ (27247B and 27252A) support"
-       depends on ISA
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called hp-plus.
-
-config HPLAN
-       tristate "HP PCLAN (27245 and other 27xxx series) support"
-       depends on ISA
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called hp.
-
 config HYDRA
        tristate "Hydra support"
        depends on ZORRO
@@ -140,18 +68,6 @@ config ARM_ETHERH
          If you have an Acorn system with one of these network cards, you
          should say Y to this option if you wish to use it with Linux.
 
-config LNE390
-       tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
-       depends on PCI && EISA && EXPERIMENTAL
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called lne390.
-
 config MAC8390
        bool "Macintosh NS 8390 based ethernet cards"
        depends on MAC
@@ -187,11 +103,7 @@ config NE2000
          without a specific driver are compatible with NE2000.
 
          If you have a PCI NE2000 card however, say N here and Y to "PCI
-         NE2000 and clone support" under "EISA, VLB, PCI and on board
-         controllers" below. If you have a NE2000 card and are running on
-         an MCA system (a bus system used on some IBM PS/2 computers and
-         laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
-         below.
+         NE2000 and clone support" below.
 
          To compile this driver as a module, choose M here. The module
          will be called ne.
@@ -226,19 +138,6 @@ config APNE
          To compile this driver as a module, choose M here: the module
          will be called apne.
 
-config NE3210
-       tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
-       depends on PCI && EISA && EXPERIMENTAL
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.  Note that this driver
-         will NOT WORK for NE3200 cards as they are completely different.
-
-         To compile this driver as a module, choose M here. The module
-         will be called ne3210.
-
 config PCMCIA_PCNET
        tristate "NE2000 compatible PCMCIA support"
        depends on PCMCIA
@@ -288,18 +187,6 @@ config ULTRA
          To compile this driver as a module, choose M here. The module
          will be called smc-ultra.
 
-config ULTRA32
-       tristate "SMC Ultra32 EISA support"
-       depends on EISA
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called smc-ultra32.
-
 config WD80x3
        tristate "WD80*3 support"
        depends on ISA
index f43038babf86e96898045502b42e081d384de28b..588954a79b2ae657bf905b0246a0b2753f72a5ed 100644 (file)
@@ -3,27 +3,17 @@
 #
 
 obj-$(CONFIG_MAC8390) += mac8390.o
-obj-$(CONFIG_AC3200) += ac3200.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_ARM_ETHERH) += etherh.o
 obj-$(CONFIG_AX88796) += ax88796.o
-obj-$(CONFIG_E2100) += e2100.o 8390.o
-obj-$(CONFIG_EL2) += 3c503.o 8390p.o
-obj-$(CONFIG_ES3210) += es3210.o 8390.o
-obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
-obj-$(CONFIG_HPLAN) += hp.o 8390p.o
 obj-$(CONFIG_HYDRA) += hydra.o 8390.o
-obj-$(CONFIG_LNE390) += lne390.o 8390.o
 obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
-obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_NE3210) += ne3210.o 8390.o
 obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
 obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
-obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
diff --git a/drivers/net/ethernet/8390/ac3200.c b/drivers/net/ethernet/8390/ac3200.c
deleted file mode 100644 (file)
index ccf0794..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */
-/*
-       Written 1993, 1994 by Donald Becker.
-       Copyright 1993 United States Government as represented by the Director,
-       National Security Agency.  This software may only be used and distributed
-       according to the terms of the GNU General Public License as modified by SRC,
-       incorporated herein by reference.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-       This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN
-       Adapter.  The programming information is from the users manual, as related
-       by glee@ardnassak.math.clemson.edu.
-
-       Changelog:
-
-       Paul Gortmaker 05/98    : add support for shared mem above 1MB.
-
-  */
-
-static const char version[] =
-       "ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "8390.h"
-
-#define DRV_NAME       "ac3200"
-
-/* Offsets from the base address. */
-#define AC_NIC_BASE    0x00
-#define AC_SA_PROM     0x16                    /* The station address PROM. */
-#define AC_ADDR0       0x00                    /* Prefix station address values. */
-#define AC_ADDR1       0x40
-#define AC_ADDR2       0x90
-#define AC_ID_PORT     0xC80
-#define AC_EISA_ID     0x0110d305
-#define AC_RESET_PORT  0xC84
-#define AC_RESET       0x00
-#define AC_ENABLE      0x01
-#define AC_CONFIG      0xC90   /* The configuration port. */
-
-#define AC_IO_EXTENT 0x20
-                                /* Actually accessed is:
-                                                                * AC_NIC_BASE (0-15)
-                                                                * AC_SA_PROM (0-5)
-                                                                * AC_ID_PORT (0-3)
-                                                                * AC_RESET_PORT
-                                                                * AC_CONFIG
-                                                                */
-
-/* Decoding of the configuration register. */
-static unsigned char config2irqmap[8] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static int addrmap[8] =
-{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000,  0xD0000, 0 };
-static const char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"};
-
-#define config2irq(configval)  config2irqmap[((configval) >> 3) & 7]
-#define config2mem(configval)  addrmap[(configval) & 7]
-#define config2name(configval) port_name[((configval) >> 6) & 3]
-
-/* First and last 8390 pages. */
-#define AC_START_PG            0x00    /* First page of 8390 TX buffer */
-#define AC_STOP_PG             0x80    /* Last page +1 of the 8390 RX ring */
-
-static int ac_probe1(int ioaddr, struct net_device *dev);
-
-static int ac_open(struct net_device *dev);
-static void ac_reset_8390(struct net_device *dev);
-static void ac_block_input(struct net_device *dev, int count,
-                                       struct sk_buff *skb, int ring_offset);
-static void ac_block_output(struct net_device *dev, const int count,
-                                                       const unsigned char *buf, const int start_page);
-static void ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                                       int ring_page);
-
-static int ac_close_card(struct net_device *dev);
-
-
-/*     Probe for the AC3200.
-
-       The AC3200 can be identified by either the EISA configuration registers,
-       or the unique value in the station address PROM.
-       */
-
-static int __init do_ac3200_probe(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-       int irq = dev->irq;
-       int mem_start = dev->mem_start;
-
-       if (ioaddr > 0x1ff)             /* Check a single specified location. */
-               return ac_probe1(ioaddr, dev);
-       else if (ioaddr > 0)            /* Don't probe at all. */
-               return -ENXIO;
-
-       if ( ! EISA_bus)
-               return -ENXIO;
-
-       for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-               if (ac_probe1(ioaddr, dev) == 0)
-                       return 0;
-               dev->irq = irq;
-               dev->mem_start = mem_start;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init ac3200_probe(int unit)
-{
-       struct net_device *dev = alloc_ei_netdev();
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_ac3200_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops ac_netdev_ops = {
-       .ndo_open               = ac_open,
-       .ndo_stop               = ac_close_card,
-
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_rx_mode        = ei_set_multicast_list,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
-#endif
-};
-
-static int __init ac_probe1(int ioaddr, struct net_device *dev)
-{
-       int i, retval;
-
-       if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
-               return -EBUSY;
-
-       if (inb_p(ioaddr + AC_ID_PORT) == 0xff) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-#ifndef final_version
-       printk(KERN_DEBUG "AC3200 ethercard configuration register is %#02x,"
-                  " EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG),
-                  inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1),
-                  inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
-#endif
-
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
-
-       printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM",
-              ioaddr/0x1000, dev->dev_addr);
-#if 0
-       /* Check the vendor ID/prefix. Redundant after checking the EISA ID */
-       if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
-               || inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1
-               || inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) {
-               printk(", not found (invalid prefix).\n");
-               retval = -ENODEV;
-               goto out;
-       }
-#endif
-
-       /* Assign and allocate the interrupt now. */
-       if (dev->irq == 0) {
-               dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
-               printk(", using");
-       } else {
-               dev->irq = irq_canonicalize(dev->irq);
-               printk(", assigning");
-       }
-
-       retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
-       if (retval) {
-               printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
-               goto out;
-       }
-
-       printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
-
-       dev->base_addr = ioaddr;
-
-#ifdef notyet
-       if (dev->mem_start)     {               /* Override the value from the board. */
-               for (i = 0; i < 7; i++)
-                       if (addrmap[i] == dev->mem_start)
-                               break;
-               if (i >= 7)
-                       i = 0;
-               outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG);
-       }
-#endif
-
-       dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
-       dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
-
-       printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
-                       dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
-
-       /*
-        *  BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
-        *  the card mem within the region covered by `normal' RAM  !!!
-        *
-        *  ioremap() will fail in that case.
-        */
-       ei_status.mem = ioremap(dev->mem_start, AC_STOP_PG*0x100);
-       if (!ei_status.mem) {
-               printk(KERN_ERR "ac3200.c: Unable to remap card memory above 1MB !!\n");
-               printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n");
-               printk(KERN_ERR "ac3200.c: Driver NOT installed.\n");
-               retval = -EINVAL;
-               goto out1;
-       }
-       printk("ac3200.c: remapped %dkB card memory to virtual address %p\n",
-                       AC_STOP_PG/4, ei_status.mem);
-
-       dev->mem_start = (unsigned long)ei_status.mem;
-       dev->mem_end = dev->mem_start + (AC_STOP_PG - AC_START_PG)*256;
-
-       ei_status.name = "AC3200";
-       ei_status.tx_start_page = AC_START_PG;
-       ei_status.rx_start_page = AC_START_PG + TX_PAGES;
-       ei_status.stop_page = AC_STOP_PG;
-       ei_status.word16 = 1;
-
-       if (ei_debug > 0)
-               printk(version);
-
-       ei_status.reset_8390 = &ac_reset_8390;
-       ei_status.block_input = &ac_block_input;
-       ei_status.block_output = &ac_block_output;
-       ei_status.get_8390_hdr = &ac_get_8390_hdr;
-
-       dev->netdev_ops = &ac_netdev_ops;
-       NS8390_init(dev, 0);
-
-       retval = register_netdev(dev);
-       if (retval)
-               goto out2;
-       return 0;
-out2:
-       if (ei_status.reg0)
-               iounmap(ei_status.mem);
-out1:
-       free_irq(dev->irq, dev);
-out:
-       release_region(ioaddr, AC_IO_EXTENT);
-       return retval;
-}
-
-static int ac_open(struct net_device *dev)
-{
-#ifdef notyet
-       /* Someday we may enable the IRQ and shared memory here. */
-       int ioaddr = dev->base_addr;
-#endif
-
-       ei_open(dev);
-       return 0;
-}
-
-static void ac_reset_8390(struct net_device *dev)
-{
-       ushort ioaddr = dev->base_addr;
-
-       outb(AC_RESET, ioaddr + AC_RESET_PORT);
-       if (ei_debug > 1) printk("resetting AC3200, t=%ld...", jiffies);
-
-       ei_status.txing = 0;
-       outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
-       if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void
-ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-       void __iomem *hdr_start = ei_status.mem + ((ring_page - AC_START_PG)<<8);
-       memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-}
-
-/*  Block input and output are easy on shared memory ethercards, the only
-       complication is when the ring buffer wraps. */
-
-static void ac_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-                                                 int ring_offset)
-{
-       void __iomem *start = ei_status.mem + ring_offset - AC_START_PG*256;
-
-       if (ring_offset + count > AC_STOP_PG*256) {
-               /* We must wrap the input move. */
-               int semi_count = AC_STOP_PG*256 - ring_offset;
-               memcpy_fromio(skb->data, start, semi_count);
-               count -= semi_count;
-               memcpy_fromio(skb->data + semi_count,
-                               ei_status.mem + TX_PAGES*256, count);
-       } else {
-               memcpy_fromio(skb->data, start, count);
-       }
-}
-
-static void ac_block_output(struct net_device *dev, int count,
-                                                       const unsigned char *buf, int start_page)
-{
-       void __iomem *shmem = ei_status.mem + ((start_page - AC_START_PG)<<8);
-
-       memcpy_toio(shmem, buf, count);
-}
-
-static int ac_close_card(struct net_device *dev)
-{
-       if (ei_debug > 1)
-               printk("%s: Shutting down ethercard.\n", dev->name);
-
-#ifdef notyet
-       /* We should someday disable shared memory and interrupts. */
-       outb(0x00, ioaddr + 6); /* Disable interrupts. */
-       free_irq(dev->irq, dev);
-#endif
-
-       ei_close(dev);
-       return 0;
-}
-
-#ifdef MODULE
-#define MAX_AC32_CARDS 4       /* Max number of AC32 cards per module */
-static struct net_device *dev_ac32[MAX_AC32_CARDS];
-static int io[MAX_AC32_CARDS];
-static int irq[MAX_AC32_CARDS];
-static int mem[MAX_AC32_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "Memory base address(es)");
-MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-static int __init ac3200_module_init(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
-               if (io[this_dev] == 0 && this_dev != 0)
-                       break;
-               dev = alloc_ei_netdev();
-               if (!dev)
-                       break;
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               dev->mem_start = mem[this_dev];         /* Currently ignored by driver */
-               if (do_ac3200_probe(dev) == 0) {
-                       dev_ac32[found++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-       /* Someday free_irq may be in ac_close_card() */
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, AC_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
-static void __exit ac3200_module_exit(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
-               struct net_device *dev = dev_ac32[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-module_init(ac3200_module_init);
-module_exit(ac3200_module_exit);
-#endif /* MODULE */
index 70dba5d01ad3cc8178318f9976a5922894a86859..cab306a9888ea5a5ac0036058eaa0290968dbbec 100644 (file)
@@ -358,7 +358,7 @@ static int ax_mii_probe(struct net_device *dev)
                return -ENODEV;
        }
 
-       ret = phy_connect_direct(dev, phy_dev, ax_handle_link_change, 0,
+       ret = phy_connect_direct(dev, phy_dev, ax_handle_link_change,
                                 PHY_INTERFACE_MODE_MII);
        if (ret) {
                netdev_err(dev, "Could not attach to PHY\n");
@@ -469,9 +469,9 @@ static void ax_get_drvinfo(struct net_device *dev,
 {
        struct platform_device *pdev = to_platform_device(dev->dev.parent);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pdev->name);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pdev->name, sizeof(info->bus_info));
 }
 
 static int ax_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/8390/e2100.c b/drivers/net/ethernet/8390/e2100.c
deleted file mode 100644 (file)
index ed55ce8..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
-/*
-       Written 1993-1994 by Donald Becker.
-
-       Copyright 1994 by Donald Becker.
-       Copyright 1993 United States Government as represented by the
-       Director, National Security Agency.  This software may be used and
-       distributed according to the terms of the GNU General Public License,
-       incorporated herein by reference.
-
-       This is a driver for the Cabletron E2100 series ethercards.
-
-       The Author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-       The E2100 series ethercard is a fairly generic shared memory 8390
-       implementation.  The only unusual aspect is the way the shared memory
-       registers are set: first you do an inb() in what is normally the
-       station address region, and the low three bits of next outb() *address*
-       is used as the write value for that register.  Either someone wasn't
-       too used to dem bit en bites, or they were trying to obfuscate the
-       programming interface.
-
-       There is an additional complication when setting the window on the packet
-       buffer.  You must first do a read into the packet buffer region with the
-       low 8 address bits the address setting the page for the start of the packet
-       buffer window, and then do the above operation.  See mem_on() for details.
-
-       One bug on the chip is that even a hard reset won't disable the memory
-       window, usually resulting in a hung machine if mem_off() isn't called.
-       If this happens, you must power down the machine for about 30 seconds.
-*/
-
-static const char version[] =
-       "e2100.c:v1.01 7/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "e2100"
-
-static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
-
-/* Offsets from the base_addr.
-   Read from the ASIC register, and the low three bits of the next outb()
-   address is used to set the corresponding register. */
-#define E21_NIC_OFFSET  0              /* Offset to the 8390 NIC. */
-#define E21_ASIC               0x10
-#define E21_MEM_ENABLE 0x10
-#define  E21_MEM_ON            0x05    /* Enable memory in 16 bit mode. */
-#define  E21_MEM_ON_8  0x07    /* Enable memory in  8 bit mode. */
-#define E21_MEM_BASE   0x11
-#define E21_IRQ_LOW            0x12    /* The low three bits of the IRQ number. */
-#define E21_IRQ_HIGH   0x14    /* The high IRQ bit and media select ...  */
-#define E21_MEDIA              0x14    /* (alias). */
-#define  E21_ALT_IFPORT 0x02   /* Set to use the other (BNC,AUI) port. */
-#define  E21_BIG_MEM   0x04    /* Use a bigger (64K) buffer (we don't) */
-#define E21_SAPROM             0x10    /* Offset to station address data. */
-#define E21_IO_EXTENT   0x20
-
-static inline void mem_on(short port, volatile char __iomem *mem_base,
-                                                 unsigned char start_page )
-{
-       /* This is a little weird: set the shared memory window by doing a
-          read.  The low address bits specify the starting page. */
-       readb(mem_base+start_page);
-       inb(port + E21_MEM_ENABLE);
-       outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
-}
-
-static inline void mem_off(short port)
-{
-       inb(port + E21_MEM_ENABLE);
-       outb(0x00, port + E21_MEM_ENABLE);
-}
-
-/* In other drivers I put the TX pages first, but the E2100 window circuitry
-   is designed to have a 4K Tx region last. The windowing circuitry wraps the
-   window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
-   appear contiguously in the window. */
-#define E21_RX_START_PG                0x00    /* First page of RX buffer */
-#define E21_RX_STOP_PG         0x30    /* Last page +1 of RX ring */
-#define E21_BIG_RX_STOP_PG     0xF0    /* Last page +1 of RX ring */
-#define E21_TX_START_PG                E21_RX_STOP_PG  /* First page of TX buffer */
-
-static int e21_probe1(struct net_device *dev, int ioaddr);
-
-static int e21_open(struct net_device *dev);
-static void e21_reset_8390(struct net_device *dev);
-static void e21_block_input(struct net_device *dev, int count,
-                                                  struct sk_buff *skb, int ring_offset);
-static void e21_block_output(struct net_device *dev, int count,
-                                                        const unsigned char *buf, int start_page);
-static void e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                                                       int ring_page);
-static int e21_open(struct net_device *dev);
-static int e21_close(struct net_device *dev);
-
-
-/*  Probe for the E2100 series ethercards.  These cards have an 8390 at the
-       base address and the station address at both offset 0x10 and 0x18.  I read
-       the station address from offset 0x18 to avoid the dataport of NE2000
-       ethercards, and look for Ctron's unique ID (first three octets of the
-       station address).
- */
-
-static int  __init do_e2100_probe(struct net_device *dev)
-{
-       int *port;
-       int base_addr = dev->base_addr;
-       int irq = dev->irq;
-
-       if (base_addr > 0x1ff)          /* Check a single specified location. */
-               return e21_probe1(dev, base_addr);
-       else if (base_addr != 0)        /* Don't probe at all. */
-               return -ENXIO;
-
-       for (port = e21_probe_list; *port; port++) {
-               dev->irq = irq;
-               if (e21_probe1(dev, *port) == 0)
-                       return 0;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init e2100_probe(int unit)
-{
-       struct net_device *dev = alloc_ei_netdev();
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_e2100_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops e21_netdev_ops = {
-       .ndo_open               = e21_open,
-       .ndo_stop               = e21_close,
-
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_rx_mode        = ei_set_multicast_list,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
-#endif
-};
-
-static int __init e21_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, status, retval;
-       unsigned char *station_addr = dev->dev_addr;
-       static unsigned version_printed;
-
-       if (!request_region(ioaddr, E21_IO_EXTENT, DRV_NAME))
-               return -EBUSY;
-
-       /* First check the station address for the Ctron prefix. */
-       if (inb(ioaddr + E21_SAPROM + 0) != 0x00 ||
-           inb(ioaddr + E21_SAPROM + 1) != 0x00 ||
-           inb(ioaddr + E21_SAPROM + 2) != 0x1d) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       /* Verify by making certain that there is a 8390 at there. */
-       outb(E8390_NODMA + E8390_STOP, ioaddr);
-       udelay(1);      /* we want to delay one I/O cycle - which is 2MHz */
-       status = inb(ioaddr);
-       if (status != 0x21 && status != 0x23) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       /* Read the station address PROM.  */
-       for (i = 0; i < 6; i++)
-               station_addr[i] = inb(ioaddr + E21_SAPROM + i);
-
-       inb(ioaddr + E21_MEDIA);                /* Point to media selection. */
-       outb(0, ioaddr + E21_ASIC);     /* and disable the secondary interface. */
-
-       if (ei_debug  &&  version_printed++ == 0)
-               printk(version);
-
-       for (i = 0; i < 6; i++)
-               printk(" %02X", station_addr[i]);
-
-       if (dev->irq < 2) {
-               static const int irqlist[] = {15, 11, 10, 12, 5, 9, 3, 4};
-               for (i = 0; i < ARRAY_SIZE(irqlist); i++)
-                       if (request_irq (irqlist[i], NULL, 0, "bogus", NULL) != -EBUSY) {
-                               dev->irq = irqlist[i];
-                               break;
-                       }
-               if (i >= ARRAY_SIZE(irqlist)) {
-                       printk(" unable to get IRQ %d.\n", dev->irq);
-                       retval = -EAGAIN;
-                       goto out;
-               }
-       } else if (dev->irq == 2)       /* Fixup luser bogosity: IRQ2 is really IRQ9 */
-               dev->irq = 9;
-
-       /* The 8390 is at the base address. */
-       dev->base_addr = ioaddr;
-
-       ei_status.name = "E2100";
-       ei_status.word16 = 1;
-       ei_status.tx_start_page = E21_TX_START_PG;
-       ei_status.rx_start_page = E21_RX_START_PG;
-       ei_status.stop_page = E21_RX_STOP_PG;
-       ei_status.saved_irq = dev->irq;
-
-       /* Check the media port used.  The port can be passed in on the
-          low mem_end bits. */
-       if (dev->mem_end & 15)
-               dev->if_port = dev->mem_end & 7;
-       else {
-               dev->if_port = 0;
-               inb(ioaddr + E21_MEDIA);        /* Turn automatic media detection on. */
-               for(i = 0; i < 6; i++)
-                       if (station_addr[i] != inb(ioaddr + E21_SAPROM + 8 + i)) {
-                               dev->if_port = 1;
-                               break;
-                       }
-       }
-
-       /* Never map in the E21 shared memory unless you are actively using it.
-          Also, the shared memory has effective only one setting -- spread all
-          over the 128K region! */
-       if (dev->mem_start == 0)
-               dev->mem_start = 0xd0000;
-
-       ei_status.mem = ioremap(dev->mem_start, 2*1024);
-       if (!ei_status.mem) {
-               printk("unable to remap memory\n");
-               retval = -EAGAIN;
-               goto out;
-       }
-
-#ifdef notdef
-       /* These values are unused.  The E2100 has a 2K window into the packet
-          buffer.  The window can be set to start on any page boundary. */
-       ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
-       dev->mem_end = ei_status.rmem_end = dev->mem_start + 2*1024;
-#endif
-
-       printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
-                  dev->if_port ? "secondary" : "primary", dev->mem_start);
-
-       ei_status.reset_8390 = &e21_reset_8390;
-       ei_status.block_input = &e21_block_input;
-       ei_status.block_output = &e21_block_output;
-       ei_status.get_8390_hdr = &e21_get_8390_hdr;
-
-       dev->netdev_ops = &e21_netdev_ops;
-       NS8390_init(dev, 0);
-
-       retval = register_netdev(dev);
-       if (retval)
-               goto out;
-       return 0;
-out:
-       release_region(ioaddr, E21_IO_EXTENT);
-       return retval;
-}
-
-static int
-e21_open(struct net_device *dev)
-{
-       short ioaddr = dev->base_addr;
-       int retval;
-
-       if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)))
-               return retval;
-
-       /* Set the interrupt line and memory base on the hardware. */
-       inb(ioaddr + E21_IRQ_LOW);
-       outb(0, ioaddr + E21_ASIC + (dev->irq & 7));
-       inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
-       outb(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
-                  + (dev->if_port ? E21_ALT_IFPORT : 0));
-       inb(ioaddr + E21_MEM_BASE);
-       outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
-
-       ei_open(dev);
-       return 0;
-}
-
-static void
-e21_reset_8390(struct net_device *dev)
-{
-       short ioaddr = dev->base_addr;
-
-       outb(0x01, ioaddr);
-       if (ei_debug > 1) printk("resetting the E2180x3 t=%ld...", jiffies);
-       ei_status.txing = 0;
-
-       /* Set up the ASIC registers, just in case something changed them. */
-
-       if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. We put the 2k window so the header page
-   appears at the start of the shared memory. */
-
-static void
-e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-
-       short ioaddr = dev->base_addr;
-       char __iomem *shared_mem = ei_status.mem;
-
-       mem_on(ioaddr, shared_mem, ring_page);
-
-#ifdef notdef
-       /* Officially this is what we are doing, but the readl() is faster */
-       memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
-#else
-       ((unsigned int*)hdr)[0] = readl(shared_mem);
-#endif
-
-       /* Turn off memory access: we would need to reprogram the window anyway. */
-       mem_off(ioaddr);
-
-}
-
-/*  Block input and output are easy on shared memory ethercards.
-       The E21xx makes block_input() especially easy by wrapping the top
-       ring buffer to the bottom automatically. */
-static void
-e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-       short ioaddr = dev->base_addr;
-       char __iomem *shared_mem = ei_status.mem;
-
-       mem_on(ioaddr, shared_mem, (ring_offset>>8));
-
-       memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count);
-
-       mem_off(ioaddr);
-}
-
-static void
-e21_block_output(struct net_device *dev, int count, const unsigned char *buf,
-                                int start_page)
-{
-       short ioaddr = dev->base_addr;
-       volatile char __iomem *shared_mem = ei_status.mem;
-
-       /* Set the shared memory window start by doing a read, with the low address
-          bits specifying the starting page. */
-       readb(shared_mem + start_page);
-       mem_on(ioaddr, shared_mem, start_page);
-
-       memcpy_toio(shared_mem, buf, count);
-       mem_off(ioaddr);
-}
-
-static int
-e21_close(struct net_device *dev)
-{
-       short ioaddr = dev->base_addr;
-
-       if (ei_debug > 1)
-               printk("%s: Shutting down ethercard.\n", dev->name);
-
-       free_irq(dev->irq, dev);
-       dev->irq = ei_status.saved_irq;
-
-       /* Shut off the interrupt line and secondary interface. */
-       inb(ioaddr + E21_IRQ_LOW);
-       outb(0, ioaddr + E21_ASIC);
-       inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
-       outb(0, ioaddr + E21_ASIC);
-
-       ei_close(dev);
-
-       /* Double-check that the memory has been turned off, because really
-          really bad things happen if it isn't. */
-       mem_off(ioaddr);
-
-       return 0;
-}
-
-
-#ifdef MODULE
-#define MAX_E21_CARDS  4       /* Max number of E21 cards per module */
-static struct net_device *dev_e21[MAX_E21_CARDS];
-static int io[MAX_E21_CARDS];
-static int irq[MAX_E21_CARDS];
-static int mem[MAX_E21_CARDS];
-static int xcvr[MAX_E21_CARDS];                /* choose int. or ext. xcvr */
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param_array(xcvr, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, " memory base address(es)");
-MODULE_PARM_DESC(xcvr, "transceiver(s) (0=internal, 1=external)");
-MODULE_DESCRIPTION("Cabletron E2100 ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-
-int __init init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
-               if (io[this_dev] == 0)  {
-                       if (this_dev != 0) break; /* only autoprobe 1st one */
-                       printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n");
-               }
-               dev = alloc_ei_netdev();
-               if (!dev)
-                       break;
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               dev->mem_start = mem[this_dev];
-               dev->mem_end = xcvr[this_dev];  /* low 4bits = xcvr sel. */
-               if (do_e2100_probe(dev) == 0) {
-                       dev_e21[found++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-       /* NB: e21_close() handles free_irq */
-       iounmap(ei_status.mem);
-       release_region(dev->base_addr, E21_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
-               struct net_device *dev = dev_e21[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/es3210.c b/drivers/net/ethernet/8390/es3210.c
deleted file mode 100644 (file)
index ba1b5c9..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
-       es3210.c
-
-       Linux driver for Racal-Interlan ES3210 EISA Network Adapter
-
-       Copyright (C) 1996, Paul Gortmaker.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       Information and Code Sources:
-
-       1) The existing myriad of Linux 8390 drivers written by Donald Becker.
-
-       2) Once again Russ Nelson's asm packet driver provided additional info.
-
-       3) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
-          Too bad it doesn't work -- see below.
-
-       The ES3210 is an EISA shared memory NS8390 implementation. Note
-       that all memory copies to/from the board must be 32bit transfers.
-       Which rules out using eth_io_copy_and_sum() in this driver.
-
-       Apparently there are two slightly different revisions of the
-       card, since there are two distinct EISA cfg files (!rii0101.cfg
-       and !rii0102.cfg) One has media select in the cfg file and the
-       other doesn't. Hopefully this will work with either.
-
-       That is about all I can tell you about it, having never actually
-       even seen one of these cards. :)  Try http://www.interlan.com
-       if you want more info.
-
-       Thanks go to Mark Salazar for testing v0.02 of this driver.
-
-       Bugs, to-fix, etc:
-
-       1) The EISA cfg ports that are *supposed* to have the IRQ and shared
-          mem values just read 0xff all the time. Hrrmpf. Apparently the
-          same happens with the packet driver as the code for reading
-          these registers is disabled there. In the meantime, boot with:
-          ether=<IRQ>,0,0x<shared_mem_addr>,eth0 to override the IRQ and
-          shared memory detection. (The i/o port detection is okay.)
-
-       2) Module support currently untested. Probably works though.
-
-*/
-
-static const char version[] =
-       "es3210.c: Driver revision v0.03, 14/09/96\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-static int es_probe1(struct net_device *dev, int ioaddr);
-
-static void es_reset_8390(struct net_device *dev);
-
-static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void es_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page);
-
-#define ES_START_PG    0x00    /* First page of TX buffer              */
-#define ES_STOP_PG     0x40    /* Last page +1 of RX ring              */
-
-#define ES_IO_EXTENT   0x37    /* The cfg file says 0xc90 -> 0xcc7     */
-#define ES_ID_PORT     0xc80   /* Same for all EISA cards              */
-#define ES_SA_PROM     0xc90   /* Start of e'net addr.                 */
-#define ES_RESET_PORT  0xc84   /* From the packet driver source        */
-#define ES_NIC_OFFSET  0xca0   /* Hello, the 8390 is *here*            */
-
-#define ES_ADDR0       0x02    /* 3 byte vendor prefix                 */
-#define ES_ADDR1       0x07
-#define ES_ADDR2       0x01
-
-/*
- * Two card revisions. EISA ID's are always rev. minor, rev. major,, and
- * then the three vendor letters stored in 5 bits each, with an "a" = 1.
- * For eg: "rii" = 10010 01001 01001 = 0x4929, which is how the EISA
- * config utility determines automagically what config file(s) to use.
- */
-#define ES_EISA_ID1    0x01012949      /* !rii0101.cfg                 */
-#define ES_EISA_ID2    0x02012949      /* !rii0102.cfg                 */
-
-#define ES_CFG1                0xcc0   /* IOPORT(1) --> IOPORT(6) in cfg file  */
-#define ES_CFG2                0xcc1
-#define ES_CFG3                0xcc2
-#define ES_CFG4                0xcc3
-#define ES_CFG5                0xcc4
-#define ES_CFG6                0xc84   /* NB: 0xc84 is also "reset" port.      */
-
-/*
- *     You can OR any of the following bits together and assign it
- *     to ES_DEBUG to get verbose driver info during operation.
- *     Some of these don't do anything yet.
- */
-
-#define ES_D_PROBE     0x01
-#define ES_D_RX_PKT    0x02
-#define ES_D_TX_PKT    0x04
-#define ED_D_IRQ       0x08
-
-#define ES_DEBUG       0
-
-static unsigned char lo_irq_map[] __initdata = {3, 4, 5, 6, 7, 9, 10};
-static unsigned char hi_irq_map[] __initdata = {11, 12, 0, 14, 0, 0, 0, 15};
-
-/*
- *     Probe for the card. The best way is to read the EISA ID if it
- *     is known. Then we check the prefix of the station address
- *     PROM for a match against the Racal-Interlan assigned value.
- */
-
-static int __init do_es_probe(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-       int irq = dev->irq;
-       int mem_start = dev->mem_start;
-
-       if (ioaddr > 0x1ff)             /* Check a single specified location. */
-               return es_probe1(dev, ioaddr);
-       else if (ioaddr > 0)            /* Don't probe at all. */
-               return -ENXIO;
-
-       if (!EISA_bus) {
-#if ES_DEBUG & ES_D_PROBE
-               printk("es3210.c: Not EISA bus. Not probing high ports.\n");
-#endif
-               return -ENXIO;
-       }
-
-       /* EISA spec allows for up to 16 slots, but 8 is typical. */
-       for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-               if (es_probe1(dev, ioaddr) == 0)
-                       return 0;
-               dev->irq = irq;
-               dev->mem_start = mem_start;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init es_probe(int unit)
-{
-       struct net_device *dev = alloc_ei_netdev();
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_es_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static int __init es_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, retval;
-       unsigned long eisa_id;
-
-       if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
-               return -ENODEV;
-
-#if ES_DEBUG & ES_D_PROBE
-       printk("es3210.c: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + ES_ID_PORT));
-       printk("es3210.c: config regs: %#x %#x %#x %#x %#x %#x\n",
-               inb(ioaddr + ES_CFG1), inb(ioaddr + ES_CFG2), inb(ioaddr + ES_CFG3),
-               inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
-#endif
-
-/*     Check the EISA ID of the card. */
-       eisa_id = inl(ioaddr + ES_ID_PORT);
-       if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       for (i = 0; i < ETH_ALEN ; i++)
-               dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
-
-/*     Check the Racal vendor ID as well. */
-       if (dev->dev_addr[0] != ES_ADDR0 ||
-           dev->dev_addr[1] != ES_ADDR1 ||
-           dev->dev_addr[2] != ES_ADDR2) {
-               printk("es3210.c: card not found %pM (invalid_prefix).\n",
-                      dev->dev_addr);
-               retval = -ENODEV;
-               goto out;
-       }
-
-       printk("es3210.c: ES3210 rev. %ld at %#x, node %pM",
-              eisa_id>>24, ioaddr, dev->dev_addr);
-
-       /* Snarf the interrupt now. */
-       if (dev->irq == 0) {
-               unsigned char hi_irq = inb(ioaddr + ES_CFG2) & 0x07;
-               unsigned char lo_irq = inb(ioaddr + ES_CFG1) & 0xfe;
-
-               if (hi_irq != 0) {
-                       dev->irq = hi_irq_map[hi_irq - 1];
-               } else {
-                       int i = 0;
-                       while (lo_irq > (1<<i)) i++;
-                       dev->irq = lo_irq_map[i];
-               }
-               printk(" using IRQ %d", dev->irq);
-#if ES_DEBUG & ES_D_PROBE
-               printk("es3210.c: hi_irq %#x, lo_irq %#x, dev->irq = %d\n",
-                                       hi_irq, lo_irq, dev->irq);
-#endif
-       } else {
-               if (dev->irq == 2)
-                       dev->irq = 9;                   /* Doh! */
-               printk(" assigning IRQ %d", dev->irq);
-       }
-
-       if (request_irq(dev->irq, ei_interrupt, 0, "es3210", dev)) {
-               printk (" unable to get IRQ %d.\n", dev->irq);
-               retval = -EAGAIN;
-               goto out;
-       }
-
-       if (dev->mem_start == 0) {
-               unsigned char mem_enabled = inb(ioaddr + ES_CFG2) & 0xc0;
-               unsigned char mem_bits = inb(ioaddr + ES_CFG3) & 0x07;
-
-               if (mem_enabled != 0x80) {
-                       printk(" shared mem disabled - giving up\n");
-                       retval = -ENXIO;
-                       goto out1;
-               }
-               dev->mem_start = 0xC0000 + mem_bits*0x4000;
-               printk(" using ");
-       } else {
-               printk(" assigning ");
-       }
-
-       ei_status.mem = ioremap(dev->mem_start, (ES_STOP_PG - ES_START_PG)*256);
-       if (!ei_status.mem) {
-               printk("ioremap failed - giving up\n");
-               retval = -ENXIO;
-               goto out1;
-       }
-
-       dev->mem_end = dev->mem_start + (ES_STOP_PG - ES_START_PG)*256;
-
-       printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
-
-#if ES_DEBUG & ES_D_PROBE
-       if (inb(ioaddr + ES_CFG5))
-               printk("es3210: Warning - DMA channel enabled, but not used here.\n");
-#endif
-       /* Note, point at the 8390, and not the card... */
-       dev->base_addr = ioaddr + ES_NIC_OFFSET;
-
-       ei_status.name = "ES3210";
-       ei_status.tx_start_page = ES_START_PG;
-       ei_status.rx_start_page = ES_START_PG + TX_PAGES;
-       ei_status.stop_page = ES_STOP_PG;
-       ei_status.word16 = 1;
-
-       if (ei_debug > 0)
-               printk(version);
-
-       ei_status.reset_8390 = &es_reset_8390;
-       ei_status.block_input = &es_block_input;
-       ei_status.block_output = &es_block_output;
-       ei_status.get_8390_hdr = &es_get_8390_hdr;
-
-       dev->netdev_ops = &ei_netdev_ops;
-       NS8390_init(dev, 0);
-
-       retval = register_netdev(dev);
-       if (retval)
-               goto out1;
-       return 0;
-out1:
-       free_irq(dev->irq, dev);
-out:
-       release_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT);
-       return retval;
-}
-
-/*
- *     Reset as per the packet driver method. Judging by the EISA cfg
- *     file, this just toggles the "Board Enable" bits (bit 2 and 0).
- */
-
-static void es_reset_8390(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-       unsigned long end;
-
-       outb(0x04, ioaddr + ES_RESET_PORT);
-       if (ei_debug > 1) printk("%s: resetting the ES3210...", dev->name);
-
-       end = jiffies + 2*HZ/100;
-        while ((signed)(end - jiffies) > 0) continue;
-
-       ei_status.txing = 0;
-       outb(0x01, ioaddr + ES_RESET_PORT);
-       if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- *     Note: In the following three functions is the implicit assumption
- *     that the associated memcpy will only use "rep; movsl" as long as
- *     we keep the counts as some multiple of doublewords. This is a
- *     requirement of the hardware, and also prevents us from using
- *     eth_io_copy_and_sum() since we can't guarantee it will limit
- *     itself to doubleword access.
- */
-
-/*
- *     Grab the 8390 specific header. Similar to the block_input routine, but
- *     we don't need to be concerned with ring wrap as the header will be at
- *     the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-       void __iomem *hdr_start = ei_status.mem + ((ring_page - ES_START_PG)<<8);
-       memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-       hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
-}
-
-/*
- *     Block input and output are easy on shared memory ethercards, the only
- *     complication is when the ring buffer wraps. The count will already
- *     be rounded up to a doubleword value via es_get_8390_hdr() above.
- */
-
-static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-                                                 int ring_offset)
-{
-       void __iomem *xfer_start = ei_status.mem + ring_offset - ES_START_PG*256;
-
-       if (ring_offset + count > ES_STOP_PG*256) {
-               /* Packet wraps over end of ring buffer. */
-               int semi_count = ES_STOP_PG*256 - ring_offset;
-               memcpy_fromio(skb->data, xfer_start, semi_count);
-               count -= semi_count;
-               memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
-       } else {
-               /* Packet is in one chunk. */
-               memcpy_fromio(skb->data, xfer_start, count);
-       }
-}
-
-static void es_block_output(struct net_device *dev, int count,
-                               const unsigned char *buf, int start_page)
-{
-       void __iomem *shmem = ei_status.mem + ((start_page - ES_START_PG)<<8);
-
-       count = (count + 3) & ~3;     /* Round up to doubleword */
-       memcpy_toio(shmem, buf, count);
-}
-
-#ifdef MODULE
-#define MAX_ES_CARDS   4       /* Max number of ES3210 cards per module */
-#define NAMELEN                8       /* # of chars for storing dev->name */
-static struct net_device *dev_es3210[MAX_ES_CARDS];
-static int io[MAX_ES_CARDS];
-static int irq[MAX_ES_CARDS];
-static int mem[MAX_ES_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "memory base address(es)");
-MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
-               if (io[this_dev] == 0 && this_dev != 0)
-                       break;
-               dev = alloc_ei_netdev();
-               if (!dev)
-                       break;
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               dev->mem_start = mem[this_dev];
-               if (do_es_probe(dev) == 0) {
-                       dev_es3210[found++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, ES_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
-void __exit
-cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
-               struct net_device *dev = dev_es3210[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ethernet/8390/hp-plus.c b/drivers/net/ethernet/8390/hp-plus.c
deleted file mode 100644 (file)
index 52f70f9..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
-/*
-       Written 1994 by Donald Becker.
-
-       This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
-       These cards are sold under several model numbers, usually 2724*.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-       As is often the case, a great deal of credit is owed to Russ Nelson.
-       The Crynwr packet driver was my primary source of HP-specific
-       programming information.
-*/
-
-static const char version[] =
-"hp-plus.c:v1.10 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-
-#include <linux/string.h>              /* Important -- this inlines word moves. */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "hp-plus"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int hpplus_portlist[] __initdata =
-{0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
-
-/*
-   The HP EtherTwist chip implementation is a fairly routine DP8390
-   implementation.  It allows both shared memory and programmed-I/O buffer
-   access, using a custom interface for both.  The programmed-I/O mode is
-   entirely implemented in the HP EtherTwist chip, bypassing the problem
-   ridden built-in 8390 facilities used on NE2000 designs.  The shared
-   memory mode is likewise special, with an offset register used to make
-   packets appear at the shared memory base.  Both modes use a base and bounds
-   page register to hide the Rx ring buffer wrap -- a packet that spans the
-   end of physical buffer memory appears continuous to the driver. (c.f. the
-   3c503 and Cabletron E2100)
-
-   A special note: the internal buffer of the board is only 8 bits wide.
-   This lays several nasty traps for the unaware:
-   - the 8390 must be programmed for byte-wide operations
-   - all I/O and memory operations must work on whole words (the access
-     latches are serially preloaded and have no byte-swapping ability).
-
-   This board is laid out in I/O space much like the earlier HP boards:
-   the first 16 locations are for the board registers, and the second 16 are
-   for the 8390.  The board is easy to identify, with both a dedicated 16 bit
-   ID register and a constant 0x530* value in the upper bits of the paging
-   register.
-*/
-
-#define HP_ID                  0x00    /* ID register, always 0x4850. */
-#define HP_PAGING              0x02    /* Registers visible @ 8-f, see PageName. */
-#define HPP_OPTION             0x04    /* Bitmapped options, see HP_Option.    */
-#define HPP_OUT_ADDR   0x08    /* I/O output location in Perf_Page.    */
-#define HPP_IN_ADDR            0x0A    /* I/O input location in Perf_Page.             */
-#define HP_DATAPORT            0x0c    /* I/O data transfer in Perf_Page.              */
-#define NIC_OFFSET             0x10    /* Offset to the 8390 registers.                */
-#define HP_IO_EXTENT   32
-
-#define HP_START_PG            0x00    /* First page of TX buffer */
-#define HP_STOP_PG             0x80    /* Last page +1 of RX ring */
-
-/* The register set selected in HP_PAGING. */
-enum PageName {
-       Perf_Page = 0,                          /* Normal operation. */
-       MAC_Page = 1,                           /* The ethernet address (+checksum). */
-       HW_Page = 2,                            /* EEPROM-loaded hardware parameters. */
-       LAN_Page = 4,                           /* Transceiver selection, testing, etc. */
-       ID_Page = 6 };
-
-/* The bit definitions for the HPP_OPTION register. */
-enum HP_Option {
-       NICReset = 1, ChipReset = 2,    /* Active low, really UNreset. */
-       EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
-       MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
-
-static int hpp_probe1(struct net_device *dev, int ioaddr);
-
-static void hpp_reset_8390(struct net_device *dev);
-static int hpp_open(struct net_device *dev);
-static int hpp_close(struct net_device *dev);
-static void hpp_mem_block_input(struct net_device *dev, int count,
-                                                 struct sk_buff *skb, int ring_offset);
-static void hpp_mem_block_output(struct net_device *dev, int count,
-                                                       const unsigned char *buf, int start_page);
-static void hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                                                 int ring_page);
-static void hpp_io_block_input(struct net_device *dev, int count,
-                                                 struct sk_buff *skb, int ring_offset);
-static void hpp_io_block_output(struct net_device *dev, int count,
-                                                       const unsigned char *buf, int start_page);
-static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                                                 int ring_page);
-
-
-/*     Probe a list of addresses for an HP LAN+ adaptor.
-       This routine is almost boilerplate. */
-
-static int __init do_hpp_probe(struct net_device *dev)
-{
-       int i;
-       int base_addr = dev->base_addr;
-       int irq = dev->irq;
-
-       if (base_addr > 0x1ff)          /* Check a single specified location. */
-               return hpp_probe1(dev, base_addr);
-       else if (base_addr != 0)        /* Don't probe at all. */
-               return -ENXIO;
-
-       for (i = 0; hpplus_portlist[i]; i++) {
-               if (hpp_probe1(dev, hpplus_portlist[i]) == 0)
-                       return 0;
-               dev->irq = irq;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init hp_plus_probe(int unit)
-{
-       struct net_device *dev = alloc_eip_netdev();
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_hpp_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops hpp_netdev_ops = {
-       .ndo_open               = hpp_open,
-       .ndo_stop               = hpp_close,
-       .ndo_start_xmit         = eip_start_xmit,
-       .ndo_tx_timeout         = eip_tx_timeout,
-       .ndo_get_stats          = eip_get_stats,
-       .ndo_set_rx_mode        = eip_set_multicast_list,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = eip_poll,
-#endif
-};
-
-
-/* Do the interesting part of the probe at a single address. */
-static int __init hpp_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, retval;
-       unsigned char checksum = 0;
-       const char name[] = "HP-PC-LAN+";
-       int mem_start;
-       static unsigned version_printed;
-
-       if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
-               return -EBUSY;
-
-       /* Check for the HP+ signature, 50 48 0x 53. */
-       if (inw(ioaddr + HP_ID) != 0x4850 ||
-           (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       if (ei_debug  &&  version_printed++ == 0)
-               printk(version);
-
-       printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
-
-       /* Retrieve and checksum the station address. */
-       outw(MAC_Page, ioaddr + HP_PAGING);
-
-       for(i = 0; i < ETH_ALEN; i++) {
-               unsigned char inval = inb(ioaddr + 8 + i);
-               dev->dev_addr[i] = inval;
-               checksum += inval;
-       }
-       checksum += inb(ioaddr + 14);
-
-       printk("%pM", dev->dev_addr);
-
-       if (checksum != 0xff) {
-               printk(" bad checksum %2.2x.\n", checksum);
-               retval = -ENODEV;
-               goto out;
-       } else {
-               /* Point at the Software Configuration Flags. */
-               outw(ID_Page, ioaddr + HP_PAGING);
-               printk(" ID %4.4x", inw(ioaddr + 12));
-       }
-
-       /* Read the IRQ line. */
-       outw(HW_Page, ioaddr + HP_PAGING);
-       {
-               int irq = inb(ioaddr + 13) & 0x0f;
-               int option = inw(ioaddr + HPP_OPTION);
-
-               dev->irq = irq;
-               if (option & MemEnable) {
-                       mem_start = inw(ioaddr + 9) << 8;
-                       printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
-               } else {
-                       mem_start = 0;
-                       printk(", IRQ %d, programmed-I/O mode.\n", irq);
-               }
-       }
-
-       /* Set the wrap registers for string I/O reads.   */
-       outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
-
-       /* Set the base address to point to the NIC, not the "real" base! */
-       dev->base_addr = ioaddr + NIC_OFFSET;
-
-       dev->netdev_ops = &hpp_netdev_ops;
-
-       ei_status.name = name;
-       ei_status.word16 = 0;           /* Agggghhhhh! Debug time: 2 days! */
-       ei_status.tx_start_page = HP_START_PG;
-       ei_status.rx_start_page = HP_START_PG + TX_PAGES/2;
-       ei_status.stop_page = HP_STOP_PG;
-
-       ei_status.reset_8390 = &hpp_reset_8390;
-       ei_status.block_input = &hpp_io_block_input;
-       ei_status.block_output = &hpp_io_block_output;
-       ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
-
-       /* Check if the memory_enable flag is set in the option register. */
-       if (mem_start) {
-               ei_status.block_input = &hpp_mem_block_input;
-               ei_status.block_output = &hpp_mem_block_output;
-               ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
-               dev->mem_start = mem_start;
-               ei_status.mem = ioremap(mem_start,
-                                       (HP_STOP_PG - HP_START_PG)*256);
-               if (!ei_status.mem) {
-                       retval = -ENOMEM;
-                       goto out;
-               }
-               ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256;
-               dev->mem_end = ei_status.rmem_end
-                       = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
-       }
-
-       outw(Perf_Page, ioaddr + HP_PAGING);
-       NS8390p_init(dev, 0);
-       /* Leave the 8390 and HP chip reset. */
-       outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
-
-       retval = register_netdev(dev);
-       if (retval)
-               goto out1;
-       return 0;
-out1:
-       iounmap(ei_status.mem);
-out:
-       release_region(ioaddr, HP_IO_EXTENT);
-       return retval;
-}
-
-static int
-hpp_open(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       int option_reg;
-       int retval;
-
-       if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
-           return retval;
-       }
-
-       /* Reset the 8390 and HP chip. */
-       option_reg = inw(ioaddr + HPP_OPTION);
-       outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
-       udelay(5);
-       /* Unreset the board and enable interrupts. */
-       outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
-
-       /* Set the wrap registers for programmed-I/O operation.   */
-       outw(HW_Page, ioaddr + HP_PAGING);
-       outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
-
-       /* Select the operational page. */
-       outw(Perf_Page, ioaddr + HP_PAGING);
-
-       return eip_open(dev);
-}
-
-static int
-hpp_close(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       int option_reg = inw(ioaddr + HPP_OPTION);
-
-       free_irq(dev->irq, dev);
-       eip_close(dev);
-       outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
-                ioaddr + HPP_OPTION);
-
-       return 0;
-}
-
-static void
-hpp_reset_8390(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       int option_reg = inw(ioaddr + HPP_OPTION);
-
-       if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
-
-       outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
-       /* Pause a few cycles for the hardware reset to take place. */
-       udelay(5);
-       ei_status.txing = 0;
-       outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
-
-       udelay(5);
-
-
-       if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
-               printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-
-       if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-}
-
-/* The programmed-I/O version of reading the 4 byte 8390 specific header.
-   Note that transfer with the EtherTwist+ must be on word boundaries. */
-
-static void
-hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-
-       outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
-       insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-}
-
-/* Block input and output, similar to the Crynwr packet driver. */
-
-static void
-hpp_io_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       char *buf = skb->data;
-
-       outw(ring_offset, ioaddr + HPP_IN_ADDR);
-       insw(ioaddr + HP_DATAPORT, buf, count>>1);
-       if (count & 0x01)
-        buf[count-1] = inw(ioaddr + HP_DATAPORT);
-}
-
-/* The corresponding shared memory versions of the above 2 functions. */
-
-static void
-hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       int option_reg = inw(ioaddr + HPP_OPTION);
-
-       outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
-       outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
-       memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr));
-       outw(option_reg, ioaddr + HPP_OPTION);
-       hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3;        /* Round up allocation. */
-}
-
-static void
-hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       int option_reg = inw(ioaddr + HPP_OPTION);
-
-       outw(ring_offset, ioaddr + HPP_IN_ADDR);
-
-       outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
-
-       /* Caution: this relies on get_8390_hdr() rounding up count!
-          Also note that we *can't* use eth_io_copy_and_sum() because
-          it will not always copy "count" bytes (e.g. padded IP).  */
-
-       memcpy_fromio(skb->data, ei_status.mem, count);
-       outw(option_reg, ioaddr + HPP_OPTION);
-}
-
-/* A special note: we *must* always transfer >=16 bit words.
-   It's always safe to round up, so we do. */
-static void
-hpp_io_block_output(struct net_device *dev, int count,
-                                       const unsigned char *buf, int start_page)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
-       outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
-}
-
-static void
-hpp_mem_block_output(struct net_device *dev, int count,
-                               const unsigned char *buf, int start_page)
-{
-       int ioaddr = dev->base_addr - NIC_OFFSET;
-       int option_reg = inw(ioaddr + HPP_OPTION);
-
-       outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
-       outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
-       memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
-       outw(option_reg, ioaddr + HPP_OPTION);
-}
-
-
-#ifdef MODULE
-#define MAX_HPP_CARDS  4       /* Max number of HPP cards per module */
-static struct net_device *dev_hpp[MAX_HPP_CARDS];
-static int io[MAX_HPP_CARDS];
-static int irq[MAX_HPP_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O port address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
-MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
-               if (io[this_dev] == 0)  {
-                       if (this_dev != 0) break; /* only autoprobe 1st one */
-                       printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
-               }
-               dev = alloc_eip_netdev();
-               if (!dev)
-                       break;
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               if (do_hpp_probe(dev) == 0) {
-                       dev_hpp[found++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-       /* NB: hpp_close() handles free_irq */
-       iounmap(ei_status.mem);
-       release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
-               struct net_device *dev = dev_hpp[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/hp.c b/drivers/net/ethernet/8390/hp.c
deleted file mode 100644 (file)
index 37fa89a..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-/* hp.c: A HP LAN ethernet driver for linux. */
-/*
-       Written 1993-94 by Donald Becker.
-
-       Copyright 1993 United States Government as represented by the
-       Director, National Security Agency.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-       This is a driver for the HP PC-LAN adaptors.
-
-       Sources:
-         The Crynwr packet driver.
-*/
-
-static const char version[] =
-       "hp.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "hp"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int hppclan_portlist[] __initdata =
-{ 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
-
-#define HP_IO_EXTENT   32
-
-#define HP_DATAPORT            0x0c    /* "Remote DMA" data port. */
-#define HP_ID                  0x07
-#define HP_CONFIGURE   0x08    /* Configuration register. */
-#define         HP_RUN                 0x01    /* 1 == Run, 0 == reset. */
-#define         HP_IRQ                 0x0E    /* Mask for software-configured IRQ line. */
-#define         HP_DATAON              0x10    /* Turn on dataport */
-#define NIC_OFFSET             0x10    /* Offset the 8390 registers. */
-
-#define HP_START_PG            0x00    /* First page of TX buffer */
-#define HP_8BSTOP_PG   0x80    /* Last page +1 of RX ring */
-#define HP_16BSTOP_PG  0xFF    /* Same, for 16 bit cards. */
-
-static int hp_probe1(struct net_device *dev, int ioaddr);
-
-static void hp_reset_8390(struct net_device *dev);
-static void hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                                       int ring_page);
-static void hp_block_input(struct net_device *dev, int count,
-                                       struct sk_buff *skb , int ring_offset);
-static void hp_block_output(struct net_device *dev, int count,
-                                                       const unsigned char *buf, int start_page);
-
-static void hp_init_card(struct net_device *dev);
-
-/* The map from IRQ number to HP_CONFIGURE register setting. */
-/* My default is IRQ5               0  1  2  3  4  5  6  7  8  9 10 11 */
-static char irqmap[16] __initdata= { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
-
-
-/*     Probe for an HP LAN adaptor.
-       Also initialize the card and fill in STATION_ADDR with the station
-       address. */
-
-static int __init do_hp_probe(struct net_device *dev)
-{
-       int i;
-       int base_addr = dev->base_addr;
-       int irq = dev->irq;
-
-       if (base_addr > 0x1ff)          /* Check a single specified location. */
-               return hp_probe1(dev, base_addr);
-       else if (base_addr != 0)        /* Don't probe at all. */
-               return -ENXIO;
-
-       for (i = 0; hppclan_portlist[i]; i++) {
-               if (hp_probe1(dev, hppclan_portlist[i]) == 0)
-                       return 0;
-               dev->irq = irq;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init hp_probe(int unit)
-{
-       struct net_device *dev = alloc_eip_netdev();
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_hp_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static int __init hp_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, retval, board_id, wordmode;
-       const char *name;
-       static unsigned version_printed;
-
-       if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
-               return -EBUSY;
-
-       /* Check for the HP physical address, 08 00 09 xx xx xx. */
-       /* This really isn't good enough: we may pick up HP LANCE boards
-          also!  Avoid the lance 0x5757 signature. */
-       if (inb(ioaddr) != 0x08
-               || inb(ioaddr+1) != 0x00
-               || inb(ioaddr+2) != 0x09
-               || inb(ioaddr+14) == 0x57) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       /* Set up the parameters based on the board ID.
-          If you have additional mappings, please mail them to me -djb. */
-       if ((board_id = inb(ioaddr + HP_ID)) & 0x80) {
-               name = "HP27247";
-               wordmode = 1;
-       } else {
-               name = "HP27250";
-               wordmode = 0;
-       }
-
-       if (ei_debug  &&  version_printed++ == 0)
-               printk(version);
-
-       printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
-
-       for(i = 0; i < ETH_ALEN; i++)
-               dev->dev_addr[i] = inb(ioaddr + i);
-
-       printk(" %pM", dev->dev_addr);
-
-       /* Snarf the interrupt now.  Someday this could be moved to open(). */
-       if (dev->irq < 2) {
-               static const int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
-               static const int irq_8list[] = { 7, 5, 3, 4, 9, 0};
-               const int *irqp = wordmode ? irq_16list : irq_8list;
-               do {
-                       int irq = *irqp;
-                       if (request_irq (irq, NULL, 0, "bogus", NULL) != -EBUSY) {
-                               unsigned long cookie = probe_irq_on();
-                               /* Twinkle the interrupt, and check if it's seen. */
-                               outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
-                               outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
-                               if (irq == probe_irq_off(cookie)                 /* It's a good IRQ line! */
-                                       && request_irq (irq, eip_interrupt, 0, DRV_NAME, dev) == 0) {
-                                       printk(" selecting IRQ %d.\n", irq);
-                                       dev->irq = *irqp;
-                                       break;
-                               }
-                       }
-               } while (*++irqp);
-               if (*irqp == 0) {
-                       printk(" no free IRQ lines.\n");
-                       retval = -EBUSY;
-                       goto out;
-               }
-       } else {
-               if (dev->irq == 2)
-                       dev->irq = 9;
-               if ((retval = request_irq(dev->irq, eip_interrupt, 0, DRV_NAME, dev))) {
-                       printk (" unable to get IRQ %d.\n", dev->irq);
-                       goto out;
-               }
-       }
-
-       /* Set the base address to point to the NIC, not the "real" base! */
-       dev->base_addr = ioaddr + NIC_OFFSET;
-       dev->netdev_ops = &eip_netdev_ops;
-
-       ei_status.name = name;
-       ei_status.word16 = wordmode;
-       ei_status.tx_start_page = HP_START_PG;
-       ei_status.rx_start_page = HP_START_PG + TX_PAGES;
-       ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
-
-       ei_status.reset_8390 = hp_reset_8390;
-       ei_status.get_8390_hdr = hp_get_8390_hdr;
-       ei_status.block_input = hp_block_input;
-       ei_status.block_output = hp_block_output;
-       hp_init_card(dev);
-
-       retval = register_netdev(dev);
-       if (retval)
-               goto out1;
-       return 0;
-out1:
-       free_irq(dev->irq, dev);
-out:
-       release_region(ioaddr, HP_IO_EXTENT);
-       return retval;
-}
-
-static void
-hp_reset_8390(struct net_device *dev)
-{
-       int hp_base = dev->base_addr - NIC_OFFSET;
-       int saved_config = inb_p(hp_base + HP_CONFIGURE);
-
-       if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
-       outb_p(0x00, hp_base + HP_CONFIGURE);
-       ei_status.txing = 0;
-       /* Pause just a few cycles for the hardware reset to take place. */
-       udelay(5);
-
-       outb_p(saved_config, hp_base + HP_CONFIGURE);
-       udelay(5);
-
-       if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
-               printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-
-       if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-}
-
-static void
-hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-       int nic_base = dev->base_addr;
-       int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-
-       outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-       outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
-       outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
-       outb_p(0, nic_base + EN0_RCNTHI);
-       outb_p(0, nic_base + EN0_RSARLO);       /* On page boundary */
-       outb_p(ring_page, nic_base + EN0_RSARHI);
-       outb_p(E8390_RREAD+E8390_START, nic_base);
-
-       if (ei_status.word16)
-         insw(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-       else
-         insb(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
-
-       outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-/* Block input and output, similar to the Crynwr packet driver. If you are
-   porting to a new ethercard look at the packet driver source for hints.
-   The HP LAN doesn't use shared memory -- we put the packet
-   out through the "remote DMA" dataport. */
-
-static void
-hp_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-       int nic_base = dev->base_addr;
-       int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-       int xfer_count = count;
-       char *buf = skb->data;
-
-       outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-       outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
-       outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-       outb_p(count >> 8, nic_base + EN0_RCNTHI);
-       outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
-       outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
-       outb_p(E8390_RREAD+E8390_START, nic_base);
-       if (ei_status.word16) {
-         insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
-         if (count & 0x01)
-               buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
-       } else {
-               insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
-       }
-       /* This is for the ALPHA version only, remove for later releases. */
-       if (ei_debug > 0) {                     /* DMA termination address check... */
-         int high = inb_p(nic_base + EN0_RSARHI);
-         int low = inb_p(nic_base + EN0_RSARLO);
-         int addr = (high << 8) + low;
-         /* Check only the lower 8 bits so we can ignore ring wrap. */
-         if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
-               printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
-                          dev->name, ring_offset + xfer_count, addr);
-       }
-       outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-static void
-hp_block_output(struct net_device *dev, int count,
-                               const unsigned char *buf, int start_page)
-{
-       int nic_base = dev->base_addr;
-       int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-
-       outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-       /* Round the count up for word writes.  Do we need to do this?
-          What effect will an odd byte count have on the 8390?
-          I should check someday. */
-       if (ei_status.word16 && (count & 0x01))
-         count++;
-       /* We should already be in page 0, but to be safe... */
-       outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
-
-#ifdef NE8390_RW_BUGFIX
-       /* Handle the read-before-write bug the same way as the
-          Crynwr packet driver -- the NatSemi method doesn't work. */
-       outb_p(0x42, nic_base + EN0_RCNTLO);
-       outb_p(0,       nic_base + EN0_RCNTHI);
-       outb_p(0xff, nic_base + EN0_RSARLO);
-       outb_p(0x00, nic_base + EN0_RSARHI);
-#define NE_CMD         0x00
-       outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
-       /* Make certain that the dummy read has occurred. */
-       inb_p(0x61);
-       inb_p(0x61);
-#endif
-
-       outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-       outb_p(count >> 8,       nic_base + EN0_RCNTHI);
-       outb_p(0x00, nic_base + EN0_RSARLO);
-       outb_p(start_page, nic_base + EN0_RSARHI);
-
-       outb_p(E8390_RWRITE+E8390_START, nic_base);
-       if (ei_status.word16) {
-               /* Use the 'rep' sequence for 16 bit boards. */
-               outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
-       } else {
-               outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
-       }
-
-       /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
-
-       /* This is for the ALPHA version only, remove for later releases. */
-       if (ei_debug > 0) {                     /* DMA termination address check... */
-         int high = inb_p(nic_base + EN0_RSARHI);
-         int low  = inb_p(nic_base + EN0_RSARLO);
-         int addr = (high << 8) + low;
-         if ((start_page << 8) + count != addr)
-               printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
-                          dev->name, (start_page << 8) + count, addr);
-       }
-       outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-/* This function resets the ethercard if something screws up. */
-static void __init
-hp_init_card(struct net_device *dev)
-{
-       int irq = dev->irq;
-       NS8390p_init(dev, 0);
-       outb_p(irqmap[irq&0x0f] | HP_RUN,
-                  dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
-}
-
-#ifdef MODULE
-#define MAX_HP_CARDS   4       /* Max number of HP cards per module */
-static struct net_device *dev_hp[MAX_HP_CARDS];
-static int io[MAX_HP_CARDS];
-static int irq[MAX_HP_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_DESCRIPTION("HP PC-LAN ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
-               if (io[this_dev] == 0)  {
-                       if (this_dev != 0) break; /* only autoprobe 1st one */
-                       printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n");
-               }
-               dev = alloc_eip_netdev();
-               if (!dev)
-                       break;
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               if (do_hp_probe(dev) == 0) {
-                       dev_hp[found++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
-               struct net_device *dev = dev_hp[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/lne390.c b/drivers/net/ethernet/8390/lne390.c
deleted file mode 100644 (file)
index 479409b..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
-       lne390.c
-
-       Linux driver for Mylex LNE390 EISA Network Adapter
-
-       Copyright (C) 1996-1998, Paul Gortmaker.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       Information and Code Sources:
-
-       1) Based upon framework of es3210 driver.
-       2) The existing myriad of other Linux 8390 drivers by Donald Becker.
-       3) Russ Nelson's asm packet driver provided additional info.
-       4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
-
-       The LNE390 is an EISA shared memory NS8390 implementation. Note
-       that all memory copies to/from the board must be 32bit transfers.
-       There are two versions of the card: the lne390a and the lne390b.
-       Going by the EISA cfg files, the "a" has jumpers to select between
-       BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU.
-       The shared memory address selection is also slightly different.
-       Note that shared memory address > 1MB are supported with this driver.
-
-       You can try <http://www.mylex.com> if you want more info, as I've
-       never even seen one of these cards.  :)
-
-       Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/01
-       - get rid of check_region
-       - no need to check if dev == NULL in lne390_probe1
-*/
-
-static const char *version =
-       "lne390.c: Driver revision v0.99.1, 01/09/2000\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "lne390"
-
-static int lne390_probe1(struct net_device *dev, int ioaddr);
-
-static void lne390_reset_8390(struct net_device *dev);
-
-static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void lne390_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
-
-#define LNE390_START_PG                0x00    /* First page of TX buffer      */
-#define LNE390_STOP_PG         0x80    /* Last page +1 of RX ring      */
-
-#define LNE390_ID_PORT         0xc80   /* Same for all EISA cards      */
-#define LNE390_IO_EXTENT       0x20
-#define LNE390_SA_PROM         0x16    /* Start of e'net addr.         */
-#define LNE390_RESET_PORT      0xc84   /* From the pkt driver source   */
-#define LNE390_NIC_OFFSET      0x00    /* Hello, the 8390 is *here*    */
-
-#define LNE390_ADDR0           0x00    /* 3 byte vendor prefix         */
-#define LNE390_ADDR1           0x80
-#define LNE390_ADDR2           0xe5
-
-#define LNE390_ID0     0x10009835      /* 0x3598 = 01101 01100 11000 = mlx */
-#define LNE390_ID1     0x11009835      /* above is the 390A, this is 390B  */
-
-#define LNE390_CFG1            0xc84   /* NB: 0xc84 is also "reset" port. */
-#define LNE390_CFG2            0xc90
-
-/*
- *     You can OR any of the following bits together and assign it
- *     to LNE390_DEBUG to get verbose driver info during operation.
- *     Currently only the probe one is implemented.
- */
-
-#define LNE390_D_PROBE 0x01
-#define LNE390_D_RX_PKT        0x02
-#define LNE390_D_TX_PKT        0x04
-#define LNE390_D_IRQ   0x08
-
-#define LNE390_DEBUG   0
-
-static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
-static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
-
-/*
- *     Probe for the card. The best way is to read the EISA ID if it
- *     is known. Then we can check the prefix of the station address
- *     PROM for a match against the value assigned to Mylex.
- */
-
-static int __init do_lne390_probe(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-       int irq = dev->irq;
-       int mem_start = dev->mem_start;
-       int ret;
-
-       if (ioaddr > 0x1ff) {           /* Check a single specified location. */
-               if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
-                       return -EBUSY;
-               ret = lne390_probe1(dev, ioaddr);
-               if (ret)
-                       release_region(ioaddr, LNE390_IO_EXTENT);
-               return ret;
-       }
-       else if (ioaddr > 0)            /* Don't probe at all. */
-               return -ENXIO;
-
-       if (!EISA_bus) {
-#if LNE390_DEBUG & LNE390_D_PROBE
-               printk("lne390-debug: Not an EISA bus. Not probing high ports.\n");
-#endif
-               return -ENXIO;
-       }
-
-       /* EISA spec allows for up to 16 slots, but 8 is typical. */
-       for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-               if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
-                       continue;
-               if (lne390_probe1(dev, ioaddr) == 0)
-                       return 0;
-               release_region(ioaddr, LNE390_IO_EXTENT);
-               dev->irq = irq;
-               dev->mem_start = mem_start;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init lne390_probe(int unit)
-{
-       struct net_device *dev = alloc_ei_netdev();
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_lne390_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static int __init lne390_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, revision, ret;
-       unsigned long eisa_id;
-
-       if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
-
-#if LNE390_DEBUG & LNE390_D_PROBE
-       printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT));
-       printk("lne390-debug: config regs: %#x %#x\n",
-               inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2));
-#endif
-
-
-/*     Check the EISA ID of the card. */
-       eisa_id = inl(ioaddr + LNE390_ID_PORT);
-       if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) {
-               return -ENODEV;
-       }
-
-       revision = (eisa_id >> 24) & 0x01;      /* 0 = rev A, 1 rev B */
-
-#if 0
-/*     Check the Mylex vendor ID as well. Not really required. */
-       if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
-               || inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
-               || inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
-               printk("lne390.c: card not found");
-               for (i = 0; i < ETH_ALEN; i++)
-                       printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
-               printk(" (invalid prefix).\n");
-               return -ENODEV;
-       }
-#endif
-
-       for (i = 0; i < ETH_ALEN; i++)
-               dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
-       printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
-              0xa+revision, ioaddr/0x1000, dev->dev_addr);
-
-       printk("lne390.c: ");
-
-       /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
-       if (dev->irq == 0) {
-               unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3;
-               dev->irq = irq_map[irq_reg & 0x07];
-               printk("using");
-       } else {
-               /* This is useless unless we reprogram the card here too */
-               if (dev->irq == 2) dev->irq = 9;        /* Doh! */
-               printk("assigning");
-       }
-       printk(" IRQ %d,", dev->irq);
-
-       if ((ret = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) {
-               printk (" unable to get IRQ %d.\n", dev->irq);
-               return ret;
-       }
-
-       if (dev->mem_start == 0) {
-               unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07;
-
-               if (revision)   /* LNE390B */
-                       dev->mem_start = shmem_mapB[mem_reg] * 0x10000;
-               else            /* LNE390A */
-                       dev->mem_start = shmem_mapA[mem_reg] * 0x10000;
-               printk(" using ");
-       } else {
-               /* Should check for value in shmem_map and reprogram the card to use it */
-               dev->mem_start &= 0xfff0000;
-               printk(" assigning ");
-       }
-
-       printk("%dkB memory at physical address %#lx\n",
-                       LNE390_STOP_PG/4, dev->mem_start);
-
-       /*
-          BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
-          the card mem within the region covered by `normal' RAM  !!!
-
-          ioremap() will fail in that case.
-       */
-       ei_status.mem = ioremap(dev->mem_start, LNE390_STOP_PG*0x100);
-       if (!ei_status.mem) {
-               printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n");
-               printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n");
-               printk(KERN_ERR "lne390.c: Driver NOT installed.\n");
-               ret = -EAGAIN;
-               goto cleanup;
-       }
-       printk("lne390.c: remapped %dkB card memory to virtual address %p\n",
-                       LNE390_STOP_PG/4, ei_status.mem);
-
-       dev->mem_start = (unsigned long)ei_status.mem;
-       dev->mem_end = dev->mem_start + (LNE390_STOP_PG - LNE390_START_PG)*256;
-
-       /* The 8390 offset is zero for the LNE390 */
-       dev->base_addr = ioaddr;
-
-       ei_status.name = "LNE390";
-       ei_status.tx_start_page = LNE390_START_PG;
-       ei_status.rx_start_page = LNE390_START_PG + TX_PAGES;
-       ei_status.stop_page = LNE390_STOP_PG;
-       ei_status.word16 = 1;
-
-       if (ei_debug > 0)
-               printk(version);
-
-       ei_status.reset_8390 = &lne390_reset_8390;
-       ei_status.block_input = &lne390_block_input;
-       ei_status.block_output = &lne390_block_output;
-       ei_status.get_8390_hdr = &lne390_get_8390_hdr;
-
-       dev->netdev_ops = &ei_netdev_ops;
-       NS8390_init(dev, 0);
-
-       ret = register_netdev(dev);
-       if (ret)
-               goto unmap;
-       return 0;
-unmap:
-       if (ei_status.reg0)
-               iounmap(ei_status.mem);
-cleanup:
-       free_irq(dev->irq, dev);
-       return ret;
-}
-
-/*
- *     Reset as per the packet driver method. Judging by the EISA cfg
- *     file, this just toggles the "Board Enable" bits (bit 2 and 0).
- */
-
-static void lne390_reset_8390(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-
-       outb(0x04, ioaddr + LNE390_RESET_PORT);
-       if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name);
-
-       mdelay(2);
-
-       ei_status.txing = 0;
-       outb(0x01, ioaddr + LNE390_RESET_PORT);
-       if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- *     Note: In the following three functions is the implicit assumption
- *     that the associated memcpy will only use "rep; movsl" as long as
- *     we keep the counts as some multiple of doublewords. This is a
- *     requirement of the hardware, and also prevents us from using
- *     eth_io_copy_and_sum() since we can't guarantee it will limit
- *     itself to doubleword access.
- */
-
-/*
- *     Grab the 8390 specific header. Similar to the block_input routine, but
- *     we don't need to be concerned with ring wrap as the header will be at
- *     the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-       void __iomem *hdr_start = ei_status.mem + ((ring_page - LNE390_START_PG)<<8);
-       memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-       hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
-}
-
-/*
- *     Block input and output are easy on shared memory ethercards, the only
- *     complication is when the ring buffer wraps. The count will already
- *     be rounded up to a doubleword value via lne390_get_8390_hdr() above.
- */
-
-static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-                                                 int ring_offset)
-{
-       void __iomem *xfer_start = ei_status.mem + ring_offset - (LNE390_START_PG<<8);
-
-       if (ring_offset + count > (LNE390_STOP_PG<<8)) {
-               /* Packet wraps over end of ring buffer. */
-               int semi_count = (LNE390_STOP_PG<<8) - ring_offset;
-               memcpy_fromio(skb->data, xfer_start, semi_count);
-               count -= semi_count;
-               memcpy_fromio(skb->data + semi_count,
-                       ei_status.mem + (TX_PAGES<<8), count);
-       } else {
-               /* Packet is in one chunk. */
-               memcpy_fromio(skb->data, xfer_start, count);
-       }
-}
-
-static void lne390_block_output(struct net_device *dev, int count,
-                               const unsigned char *buf, int start_page)
-{
-       void __iomem *shmem = ei_status.mem + ((start_page - LNE390_START_PG)<<8);
-
-       count = (count + 3) & ~3;     /* Round up to doubleword */
-       memcpy_toio(shmem, buf, count);
-}
-
-
-#ifdef MODULE
-#define MAX_LNE_CARDS  4       /* Max number of LNE390 cards per module */
-static struct net_device *dev_lne[MAX_LNE_CARDS];
-static int io[MAX_LNE_CARDS];
-static int irq[MAX_LNE_CARDS];
-static int mem[MAX_LNE_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "memory base address(es)");
-MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
-               if (io[this_dev] == 0 && this_dev != 0)
-                       break;
-               dev = alloc_ei_netdev();
-               if (!dev)
-                       break;
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               dev->mem_start = mem[this_dev];
-               if (do_lne390_probe(dev) == 0) {
-                       dev_lne[found++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, LNE390_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
-               struct net_device *dev = dev_lne[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
-
index c0c127913dec6d471d75ae42be7d9e139329b867..587a885de259064cb2c07d25a5b12a1d8b9c08bf 100644 (file)
@@ -374,7 +374,6 @@ static int ne2k_pci_init_one(struct pci_dev *pdev,
        NS8390_init(dev, 0);
 
        memcpy(dev->dev_addr, SA_prom, dev->addr_len);
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        i = register_netdev(dev);
        if (i)
diff --git a/drivers/net/ethernet/8390/ne3210.c b/drivers/net/ethernet/8390/ne3210.c
deleted file mode 100644 (file)
index ebcdb52..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
-       ne3210.c
-
-       Linux driver for Novell NE3210 EISA Network Adapter
-
-       Copyright (C) 1998, Paul Gortmaker.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       Information and Code Sources:
-
-       1) Based upon my other EISA 8390 drivers (lne390, es3210, smc-ultra32)
-       2) The existing myriad of other Linux 8390 drivers by Donald Becker.
-       3) Info for getting IRQ and sh-mem gleaned from the EISA cfg file
-
-       The NE3210 is an EISA shared memory NS8390 implementation.  Shared
-       memory address > 1MB should work with this driver.
-
-       Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
-       around (or perhaps there are some defective/backwards cards ???)
-
-       This driver WILL NOT WORK FOR THE NE3200 - it is completely different
-       and does not use an 8390 at all.
-
-       Updated to EISA probing API 5/2003 by Marc Zyngier.
-*/
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "ne3210"
-
-static void ne3210_reset_8390(struct net_device *dev);
-
-static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void ne3210_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
-
-#define NE3210_START_PG                0x00    /* First page of TX buffer      */
-#define NE3210_STOP_PG         0x80    /* Last page +1 of RX ring      */
-
-#define NE3210_IO_EXTENT       0x20
-#define NE3210_SA_PROM         0x16    /* Start of e'net addr.         */
-#define NE3210_RESET_PORT      0xc84
-#define NE3210_NIC_OFFSET      0x00    /* Hello, the 8390 is *here*    */
-
-#define NE3210_ADDR0           0x00    /* 3 byte vendor prefix         */
-#define NE3210_ADDR1           0x00
-#define NE3210_ADDR2           0x1b
-
-#define NE3210_CFG1            0xc84   /* NB: 0xc84 is also "reset" port. */
-#define NE3210_CFG2            0xc90
-#define NE3210_CFG_EXTENT       (NE3210_CFG2 - NE3210_CFG1 + 1)
-
-/*
- *     You can OR any of the following bits together and assign it
- *     to NE3210_DEBUG to get verbose driver info during operation.
- *     Currently only the probe one is implemented.
- */
-
-#define NE3210_D_PROBE 0x01
-#define NE3210_D_RX_PKT        0x02
-#define NE3210_D_TX_PKT        0x04
-#define NE3210_D_IRQ   0x08
-
-#define NE3210_DEBUG   0x0
-
-static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
-static const char * const ifmap[] __initconst = {"UTP", "?", "BNC", "AUI"};
-static int ifmap_val[] __initdata = {
-               IF_PORT_10BASET,
-               IF_PORT_UNKNOWN,
-               IF_PORT_10BASE2,
-               IF_PORT_AUI,
-};
-
-static int __init ne3210_eisa_probe (struct device *device)
-{
-       unsigned long ioaddr, phys_mem;
-       int i, retval, port_index;
-       struct eisa_device *edev = to_eisa_device (device);
-       struct net_device *dev;
-
-       /* Allocate dev->priv and fill in 8390 specific dev fields. */
-       if (!(dev = alloc_ei_netdev ())) {
-               printk ("ne3210.c: unable to allocate memory for dev!\n");
-               return -ENOMEM;
-       }
-
-       SET_NETDEV_DEV(dev, device);
-       dev_set_drvdata(device, dev);
-       ioaddr = edev->base_addr;
-
-       if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) {
-               retval = -EBUSY;
-               goto out;
-       }
-
-       if (!request_region(ioaddr + NE3210_CFG1,
-                           NE3210_CFG_EXTENT, DRV_NAME)) {
-               retval = -EBUSY;
-               goto out1;
-       }
-
-#if NE3210_DEBUG & NE3210_D_PROBE
-       printk("ne3210-debug: probe at %#x, ID %s\n", ioaddr, edev->id.sig);
-       printk("ne3210-debug: config regs: %#x %#x\n",
-               inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
-#endif
-
-       port_index = inb(ioaddr + NE3210_CFG2) >> 6;
-       for (i = 0; i < ETH_ALEN; i++)
-               dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
-       printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
-               edev->slot, ifmap[port_index], dev->dev_addr);
-
-       /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
-       dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
-       printk("ne3210.c: using IRQ %d, ", dev->irq);
-
-       retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
-       if (retval) {
-               printk (" unable to get IRQ %d.\n", dev->irq);
-               goto out2;
-       }
-
-       phys_mem = shmem_map[inb(ioaddr + NE3210_CFG2) & 0x07] * 0x1000;
-
-       /*
-          BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
-          the card mem within the region covered by `normal' RAM  !!!
-       */
-       if (phys_mem > 1024*1024) {     /* phys addr > 1MB */
-               if (phys_mem < virt_to_phys(high_memory)) {
-                       printk(KERN_CRIT "ne3210.c: Card RAM overlaps with normal memory!!!\n");
-                       printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
-                       printk(KERN_CRIT "ne3210.c: or to an address above 0x%llx.\n",
-                               (u64)virt_to_phys(high_memory));
-                       printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
-                       retval = -EINVAL;
-                       goto out3;
-               }
-       }
-
-       if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
-               printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
-                       phys_mem);
-               goto out3;
-       }
-
-       printk("%dkB memory at physical address %#lx\n",
-              NE3210_STOP_PG/4, phys_mem);
-
-       ei_status.mem = ioremap(phys_mem, NE3210_STOP_PG*0x100);
-       if (!ei_status.mem) {
-               printk(KERN_ERR "ne3210.c: Unable to remap card memory !!\n");
-               printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
-               retval = -EAGAIN;
-               goto out4;
-       }
-       printk("ne3210.c: remapped %dkB card memory to virtual address %p\n",
-              NE3210_STOP_PG/4, ei_status.mem);
-       dev->mem_start = (unsigned long)ei_status.mem;
-       dev->mem_end = dev->mem_start + (NE3210_STOP_PG - NE3210_START_PG)*256;
-
-       /* The 8390 offset is zero for the NE3210 */
-       dev->base_addr = ioaddr;
-
-       ei_status.name = "NE3210";
-       ei_status.tx_start_page = NE3210_START_PG;
-       ei_status.rx_start_page = NE3210_START_PG + TX_PAGES;
-       ei_status.stop_page = NE3210_STOP_PG;
-       ei_status.word16 = 1;
-       ei_status.priv = phys_mem;
-
-       if (ei_debug > 0)
-               printk("ne3210 loaded.\n");
-
-       ei_status.reset_8390 = &ne3210_reset_8390;
-       ei_status.block_input = &ne3210_block_input;
-       ei_status.block_output = &ne3210_block_output;
-       ei_status.get_8390_hdr = &ne3210_get_8390_hdr;
-
-       dev->netdev_ops = &ei_netdev_ops;
-
-       dev->if_port = ifmap_val[port_index];
-
-       if ((retval = register_netdev (dev)))
-               goto out5;
-
-       NS8390_init(dev, 0);
-       return 0;
-
- out5:
-       iounmap(ei_status.mem);
- out4:
-       release_mem_region (phys_mem, NE3210_STOP_PG*0x100);
- out3:
-       free_irq (dev->irq, dev);
- out2:
-       release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
- out1:
-       release_region (ioaddr, NE3210_IO_EXTENT);
- out:
-       free_netdev (dev);
-
-       return retval;
-}
-
-static int ne3210_eisa_remove(struct device *device)
-{
-       struct net_device  *dev    = dev_get_drvdata(device);
-       unsigned long       ioaddr = to_eisa_device (device)->base_addr;
-
-       unregister_netdev (dev);
-       iounmap(ei_status.mem);
-       release_mem_region (ei_status.priv, NE3210_STOP_PG*0x100);
-       free_irq (dev->irq, dev);
-       release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
-       release_region (ioaddr, NE3210_IO_EXTENT);
-       free_netdev (dev);
-
-       return 0;
-}
-
-/*
- *     Reset by toggling the "Board Enable" bits (bit 2 and 0).
- */
-
-static void ne3210_reset_8390(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-
-       outb(0x04, ioaddr + NE3210_RESET_PORT);
-       if (ei_debug > 1) printk("%s: resetting the NE3210...", dev->name);
-
-       mdelay(2);
-
-       ei_status.txing = 0;
-       outb(0x01, ioaddr + NE3210_RESET_PORT);
-       if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- *     Note: In the following three functions is the implicit assumption
- *     that the associated memcpy will only use "rep; movsl" as long as
- *     we keep the counts as some multiple of doublewords. This is a
- *     requirement of the hardware, and also prevents us from using
- *     eth_io_copy_and_sum() since we can't guarantee it will limit
- *     itself to doubleword access.
- */
-
-/*
- *     Grab the 8390 specific header. Similar to the block_input routine, but
- *     we don't need to be concerned with ring wrap as the header will be at
- *     the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-       void __iomem *hdr_start = ei_status.mem + ((ring_page - NE3210_START_PG)<<8);
-       memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-       hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
-}
-
-/*
- *     Block input and output are easy on shared memory ethercards, the only
- *     complication is when the ring buffer wraps. The count will already
- *     be rounded up to a doubleword value via ne3210_get_8390_hdr() above.
- */
-
-static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-                                                 int ring_offset)
-{
-       void __iomem *start = ei_status.mem + ring_offset - NE3210_START_PG*256;
-
-       if (ring_offset + count > NE3210_STOP_PG*256) {
-               /* Packet wraps over end of ring buffer. */
-               int semi_count = NE3210_STOP_PG*256 - ring_offset;
-               memcpy_fromio(skb->data, start, semi_count);
-               count -= semi_count;
-               memcpy_fromio(skb->data + semi_count,
-                               ei_status.mem + TX_PAGES*256, count);
-       } else {
-               /* Packet is in one chunk. */
-               memcpy_fromio(skb->data, start, count);
-       }
-}
-
-static void ne3210_block_output(struct net_device *dev, int count,
-                               const unsigned char *buf, int start_page)
-{
-       void __iomem *shmem = ei_status.mem + ((start_page - NE3210_START_PG)<<8);
-
-       count = (count + 3) & ~3;     /* Round up to doubleword */
-       memcpy_toio(shmem, buf, count);
-}
-
-static struct eisa_device_id ne3210_ids[] = {
-       { "EGL0101" },
-       { "NVL1801" },
-       { "" },
-};
-MODULE_DEVICE_TABLE(eisa, ne3210_ids);
-
-static struct eisa_driver ne3210_eisa_driver = {
-       .id_table = ne3210_ids,
-       .driver   = {
-               .name   = "ne3210",
-               .probe  = ne3210_eisa_probe,
-               .remove = ne3210_eisa_remove,
-       },
-};
-
-MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(eisa, ne3210_ids);
-
-static int ne3210_init(void)
-{
-       return eisa_driver_register (&ne3210_eisa_driver);
-}
-
-static void ne3210_cleanup(void)
-{
-       eisa_driver_unregister (&ne3210_eisa_driver);
-}
-
-module_init (ne3210_init);
-module_exit (ne3210_cleanup);
diff --git a/drivers/net/ethernet/8390/smc-ultra32.c b/drivers/net/ethernet/8390/smc-ultra32.c
deleted file mode 100644 (file)
index 923e42a..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-/*     smc-ultra32.c: An SMC Ultra32 EISA ethernet driver for linux.
-
-Sources:
-
-       This driver is based on (cloned from) the ISA SMC Ultra driver
-       written by Donald Becker. Modifications to support the EISA
-       version of the card by Paul Gortmaker and Leonard N. Zubkoff.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-Theory of Operation:
-
-       The SMC Ultra32C card uses the SMC 83c790 chip which is also
-       found on the ISA SMC Ultra cards. It has a shared memory mode of
-       operation that makes it similar to the ISA version of the card.
-       The main difference is that the EISA card has 32KB of RAM, but
-       only an 8KB window into that memory. The EISA card also can be
-       set for a bus-mastering mode of operation via the ECU, but that
-       is not (and probably will never be) supported by this driver.
-       The ECU should be run to enable shared memory and to disable the
-       bus-mastering feature for use with linux.
-
-       By programming the 8390 to use only 8KB RAM, the modifications
-       to the ISA driver can be limited to the probe and initialization
-       code. This allows easy integration of EISA support into the ISA
-       driver. However, the driver development kit from SMC provided the
-       register information for sliding the 8KB window, and hence the 8390
-       is programmed to use the full 32KB RAM.
-
-       Unfortunately this required code changes outside the probe/init
-       routines, and thus we decided to separate the EISA driver from
-       the ISA one. In this way, ISA users don't end up with a larger
-       driver due to the EISA code, and EISA users don't end up with a
-       larger driver due to the ISA EtherEZ PIO code. The driver is
-       similar to the 3c503/16 driver, in that the window must be set
-       back to the 1st 8KB of space for access to the two 8390 Tx slots.
-
-       In testing, using only 8KB RAM (3 Tx / 5 Rx) didn't appear to
-       be a limiting factor, since the EISA bus could get packets off
-       the card fast enough, but having the use of lots of RAM as Rx
-       space is extra insurance if interrupt latencies become excessive.
-
-*/
-
-static const char *version = "smc-ultra32.c: 06/97 v1.00\n";
-
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "smc-ultra32"
-
-static int ultra32_probe1(struct net_device *dev, int ioaddr);
-static int ultra32_open(struct net_device *dev);
-static void ultra32_reset_8390(struct net_device *dev);
-static void ultra32_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                                int ring_page);
-static void ultra32_block_input(struct net_device *dev, int count,
-                               struct sk_buff *skb, int ring_offset);
-static void ultra32_block_output(struct net_device *dev, int count,
-                                const unsigned char *buf,
-                                const int start_page);
-static int ultra32_close(struct net_device *dev);
-
-#define ULTRA32_CMDREG 0       /* Offset to ASIC command register. */
-#define         ULTRA32_RESET  0x80    /* Board reset, in ULTRA32_CMDREG. */
-#define         ULTRA32_MEMENB 0x40    /* Enable the shared memory. */
-#define ULTRA32_NIC_OFFSET 16  /* NIC register offset from the base_addr. */
-#define ULTRA32_IO_EXTENT 32
-#define EN0_ERWCNT             0x08    /* Early receive warning count. */
-
-/*
- * Defines that apply only to the Ultra32 EISA card. Note that
- * "smc" = 10011 01101 00011 = 0x4da3, and hence !smc8010.cfg translates
- * into an EISA ID of 0x1080A34D
- */
-#define ULTRA32_BASE   0xca0
-#define ULTRA32_ID     0x1080a34d
-#define ULTRA32_IDPORT (-0x20) /* 0xc80 */
-/* Config regs 1->7 from the EISA !SMC8010.CFG file. */
-#define ULTRA32_CFG1   0x04    /* 0xca4 */
-#define ULTRA32_CFG2   0x05    /* 0xca5 */
-#define ULTRA32_CFG3   (-0x18) /* 0xc88 */
-#define ULTRA32_CFG4   (-0x17) /* 0xc89 */
-#define ULTRA32_CFG5   (-0x16) /* 0xc8a */
-#define ULTRA32_CFG6   (-0x15) /* 0xc8b */
-#define ULTRA32_CFG7   0x0d    /* 0xcad */
-
-static void cleanup_card(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET;
-       /* NB: ultra32_close_card() does free_irq */
-       release_region(ioaddr, ULTRA32_IO_EXTENT);
-       iounmap(ei_status.mem);
-}
-
-/*     Probe for the Ultra32.  This looks like a 8013 with the station
-       address PROM at I/O ports <base>+8 to <base>+13, with a checksum
-       following.
-*/
-
-struct net_device * __init ultra32_probe(int unit)
-{
-       struct net_device *dev;
-       int base;
-       int irq;
-       int err = -ENODEV;
-
-       if (!EISA_bus)
-               return ERR_PTR(-ENODEV);
-
-       dev = alloc_ei_netdev();
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       irq = dev->irq;
-
-       /* EISA spec allows for up to 16 slots, but 8 is typical. */
-       for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) {
-               if (ultra32_probe1(dev, base) == 0)
-                       break;
-               dev->irq = irq;
-       }
-       if (base >= 0x9000)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       cleanup_card(dev);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-
-static const struct net_device_ops ultra32_netdev_ops = {
-       .ndo_open               = ultra32_open,
-       .ndo_stop               = ultra32_close,
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_rx_mode        = ei_set_multicast_list,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
-#endif
-};
-
-static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, edge, media, retval;
-       int checksum = 0;
-       const char *model_name;
-       static unsigned version_printed;
-       /* Values from various config regs. */
-       unsigned char idreg;
-       unsigned char reg4;
-       const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
-
-       if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
-               return -EBUSY;
-
-       if (inb(ioaddr + ULTRA32_IDPORT) == 0xff ||
-           inl(ioaddr + ULTRA32_IDPORT) != ULTRA32_ID) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       media = inb(ioaddr + ULTRA32_CFG7) & 0x03;
-       edge = inb(ioaddr + ULTRA32_CFG5) & 0x08;
-       printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n",
-               ioaddr >> 12, ifmap[media],
-               (edge ? "Edge Triggered" : "Level Sensitive"));
-
-       idreg = inb(ioaddr + 7);
-       reg4 = inb(ioaddr + 4) & 0x7f;
-
-       /* Check the ID nibble. */
-       if ((idreg & 0xf0) != 0x20) {                   /* SMC Ultra */
-               retval = -ENODEV;
-               goto out;
-       }
-
-       /* Select the station address register set. */
-       outb(reg4, ioaddr + 4);
-
-       for (i = 0; i < 8; i++)
-               checksum += inb(ioaddr + 8 + i);
-       if ((checksum & 0xff) != 0xff) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       if (ei_debug  &&  version_printed++ == 0)
-               printk(version);
-
-       model_name = "SMC Ultra32";
-
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = inb(ioaddr + 8 + i);
-
-       printk("%s: %s at 0x%X, %pM",
-              dev->name, model_name, ioaddr, dev->dev_addr);
-
-       /* Switch from the station address to the alternate register set and
-          read the useful registers there. */
-       outb(0x80 | reg4, ioaddr + 4);
-
-       /* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
-       outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
-
-       /* Reset RAM addr. */
-       outb(0x00, ioaddr + 0x0b);
-
-       /* Switch back to the station address register set so that the
-          MS-DOS driver can find the card after a warm boot. */
-       outb(reg4, ioaddr + 4);
-
-       if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) {
-               printk("\nsmc-ultra32: Card RAM is disabled!  "
-                      "Run EISA config utility.\n");
-               retval = -ENODEV;
-               goto out;
-       }
-       if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0)
-               printk("\nsmc-ultra32: Ignoring Bus-Master enable bit.  "
-                      "Run EISA config utility.\n");
-
-       if (dev->irq < 2) {
-               unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
-               int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07];
-               if (irq == 0) {
-                       printk(", failed to detect IRQ line.\n");
-                       retval = -EAGAIN;
-                       goto out;
-               }
-               dev->irq = irq;
-       }
-
-       /* The 8390 isn't at the base address, so fake the offset */
-       dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET;
-
-       /* Save RAM address in the unused reg0 to avoid excess inb's. */
-       ei_status.reg0 = inb(ioaddr + ULTRA32_CFG3) & 0xfc;
-
-       dev->mem_start =  0xc0000 + ((ei_status.reg0 & 0x7c) << 11);
-
-       ei_status.name = model_name;
-       ei_status.word16 = 1;
-       ei_status.tx_start_page = 0;
-       ei_status.rx_start_page = TX_PAGES;
-       /* All Ultra32 cards have 32KB memory with an 8KB window. */
-       ei_status.stop_page = 128;
-
-       ei_status.mem = ioremap(dev->mem_start, 0x2000);
-       if (!ei_status.mem) {
-               printk(", failed to ioremap.\n");
-               retval = -ENOMEM;
-               goto out;
-       }
-       dev->mem_end = dev->mem_start + 0x1fff;
-
-       printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
-              dev->irq, dev->mem_start, dev->mem_end);
-       ei_status.block_input = &ultra32_block_input;
-       ei_status.block_output = &ultra32_block_output;
-       ei_status.get_8390_hdr = &ultra32_get_8390_hdr;
-       ei_status.reset_8390 = &ultra32_reset_8390;
-
-       dev->netdev_ops = &ultra32_netdev_ops;
-       NS8390_init(dev, 0);
-
-       return 0;
-out:
-       release_region(ioaddr, ULTRA32_IO_EXTENT);
-       return retval;
-}
-
-static int ultra32_open(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
-       int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : IRQF_SHARED;
-       int retval;
-
-       retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev);
-       if (retval)
-               return retval;
-
-       outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
-       outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
-       outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
-       outb(0x01, ioaddr + 6); /* Enable Interrupts. */
-       /* Set the early receive warning level in window 0 high enough not
-          to receive ERW interrupts. */
-       outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
-       outb(0xff, dev->base_addr + EN0_ERWCNT);
-       ei_open(dev);
-       return 0;
-}
-
-static int ultra32_close(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
-
-       netif_stop_queue(dev);
-
-       if (ei_debug > 1)
-               printk("%s: Shutting down ethercard.\n", dev->name);
-
-       outb(0x00, ioaddr + ULTRA32_CFG6); /* Disable Interrupts. */
-       outb(0x00, ioaddr + 6);         /* Disable interrupts. */
-       free_irq(dev->irq, dev);
-
-       NS8390_init(dev, 0);
-
-       return 0;
-}
-
-static void ultra32_reset_8390(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC base addr */
-
-       outb(ULTRA32_RESET, ioaddr);
-       if (ei_debug > 1) printk("resetting Ultra32, t=%ld...", jiffies);
-       ei_status.txing = 0;
-
-       outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
-       outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
-       outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
-       outb(0x01, ioaddr + 6); /* Enable Interrupts. */
-       if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void ultra32_get_8390_hdr(struct net_device *dev,
-                                struct e8390_pkt_hdr *hdr,
-                                int ring_page)
-{
-       void __iomem *hdr_start = ei_status.mem + ((ring_page & 0x1f) << 8);
-       unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
-       /* Select correct 8KB Window. */
-       outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg);
-
-#ifdef __BIG_ENDIAN
-       /* Officially this is what we are doing, but the readl() is faster */
-       /* unfortunately it isn't endian aware of the struct               */
-       memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-       hdr->count = le16_to_cpu(hdr->count);
-#else
-       ((unsigned int*)hdr)[0] = readl(hdr_start);
-#endif
-}
-
-/* Block input and output are easy on shared memory ethercards, the only
-   complication is when the ring buffer wraps, or in this case, when a
-   packet spans an 8KB boundary. Note that the current 8KB segment is
-   already set by the get_8390_hdr routine. */
-
-static void ultra32_block_input(struct net_device *dev,
-                               int count,
-                               struct sk_buff *skb,
-                               int ring_offset)
-{
-       void __iomem *xfer_start = ei_status.mem + (ring_offset & 0x1fff);
-       unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
-       if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) {
-               int semi_count = 8192 - (ring_offset & 0x1FFF);
-               memcpy_fromio(skb->data, xfer_start, semi_count);
-               count -= semi_count;
-               if (ring_offset < 96*256) {
-                       /* Select next 8KB Window. */
-                       ring_offset += semi_count;
-                       outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg);
-                       memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
-               } else {
-                       /* Select first 8KB Window. */
-                       outb(ei_status.reg0, RamReg);
-                       memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
-               }
-       } else {
-               memcpy_fromio(skb->data, xfer_start, count);
-       }
-}
-
-static void ultra32_block_output(struct net_device *dev,
-                                int count,
-                                const unsigned char *buf,
-                                int start_page)
-{
-       void __iomem *xfer_start = ei_status.mem + (start_page<<8);
-       unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
-       /* Select first 8KB Window. */
-       outb(ei_status.reg0, RamReg);
-
-       memcpy_toio(xfer_start, buf, count);
-}
-
-#ifdef MODULE
-#define MAX_ULTRA32_CARDS   4  /* Max number of Ultra cards per module */
-static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
-
-MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
-               struct net_device *dev = ultra32_probe(-1);
-               if (IS_ERR(dev))
-                       break;
-               dev_ultra[found++] = dev;
-       }
-       if (found)
-               return 0;
-       printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n");
-       return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
-               struct net_device *dev = dev_ultra[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
-
index e4ff38949112d8f245df2e481c28ba0ac7ede17c..ed956e08d38b1d835f233b4f1ba7698f75447c1b 100644 (file)
@@ -135,7 +135,6 @@ config ETHOC
 source "drivers/net/ethernet/packetengines/Kconfig"
 source "drivers/net/ethernet/pasemi/Kconfig"
 source "drivers/net/ethernet/qlogic/Kconfig"
-source "drivers/net/ethernet/racal/Kconfig"
 source "drivers/net/ethernet/realtek/Kconfig"
 source "drivers/net/ethernet/renesas/Kconfig"
 source "drivers/net/ethernet/rdc/Kconfig"
index d4473072654abcf0da782651a76c8d036f1fca9a..8268d85f944849b904ca44b749d3b5eb72b6e363 100644 (file)
@@ -53,7 +53,6 @@ obj-$(CONFIG_ETHOC) += ethoc.o
 obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/
 obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
 obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
-obj-$(CONFIG_NET_VENDOR_RACAL) += racal/
 obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
 obj-$(CONFIG_SH_ETH) += renesas/
 obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
index c1fdb8be8beeb193a565384470117e048a0db1dc..a175d0be1ae1a23e1c2f0fc920efd039a65b02ba 100644 (file)
@@ -425,8 +425,8 @@ static int mii_probe(struct net_device *dev, int phy_mode)
                return -EINVAL;
        }
 
-       phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
-                       0, phy_mode);
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
+                            &bfin_mac_adjust_link, phy_mode);
 
        if (IS_ERR(phydev)) {
                netdev_err(dev, "could not attach PHY\n");
@@ -498,10 +498,10 @@ bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, KBUILD_MODNAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, dev_name(&dev->dev));
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info));
 }
 
 static void bfin_mac_ethtool_getwol(struct net_device *dev,
@@ -647,7 +647,6 @@ static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
        if (netif_running(dev))
                return -EBUSY;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        setup_mac_addr(dev->dev_addr);
        return 0;
 }
index aa53115bb38b91d45329be5914241591da6776c7..0be2195e50340c24c5c2f5403b2f32b12c403c8e 100644 (file)
@@ -1127,10 +1127,11 @@ static void greth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in
 {
        struct greth_private *greth = netdev_priv(dev);
 
-       strncpy(info->driver, dev_driver_string(greth->dev), 32);
-       strncpy(info->version, "revision: 1.0", 32);
-       strncpy(info->bus_info, greth->dev->bus->name, 32);
-       strncpy(info->fw_version, "N/A", 32);
+       strlcpy(info->driver, dev_driver_string(greth->dev),
+               sizeof(info->driver));
+       strlcpy(info->version, "revision: 1.0", sizeof(info->version));
+       strlcpy(info->bus_info, greth->dev->bus->name, sizeof(info->bus_info));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
        info->eedump_len = 0;
        info->regdump_len = sizeof(struct greth_regs);
 }
@@ -1287,9 +1288,7 @@ static int greth_mdio_probe(struct net_device *dev)
        }
 
        ret = phy_connect_direct(dev, phy, &greth_link_change,
-                       0, greth->gbit_mac ?
-                       PHY_INTERFACE_MODE_GMII :
-                       PHY_INTERFACE_MODE_MII);
+                                greth->gbit_mac ? PHY_INTERFACE_MODE_GMII : PHY_INTERFACE_MODE_MII);
        if (ret) {
                if (netif_msg_ifup(greth))
                        dev_err(&dev->dev, "could not attach to PHY\n");
index 8350f4b37a8a00727afb56000a5c88856abad925..13d74aa4033dd44164dada90d0173efe526f9c16 100644 (file)
@@ -7,7 +7,7 @@ config NET_VENDOR_AMD
        default y
        depends on DIO || MACH_DECSTATION || MVME147 || ATARI || SUN3 || \
                   SUN3X || SBUS || PCI || ZORRO || (ISA && ISA_DMA_API) || \
-                  (ARM && ARCH_EBSA110) || ISA || EISA || MCA || PCMCIA
+                  (ARM && ARCH_EBSA110) || ISA || EISA || PCMCIA
        ---help---
          If you have a network (Ethernet) chipset belonging to this class,
          say Y.
@@ -105,19 +105,6 @@ config DECLANCE
          DEC (now Compaq) based on the AMD LANCE chipset, including the
          DEPCA series.  (This chipset is better known via the NE2100 cards.)
 
-config DEPCA
-       tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
-       depends on (ISA || EISA || MCA)
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto> as well as
-         <file:drivers/net/ethernet/amd/depca.c>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called depca.
-
 config HPLANCE
        bool "HP on-board LANCE support"
        depends on DIO
index 175caa5328c96b389476cdb5da99511b14dac810..cdd4301a973dc388a6d7f1d2a7ed5325f87d6e6b 100644 (file)
@@ -8,7 +8,6 @@ obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_DECLANCE) += declance.o
-obj-$(CONFIG_DEPCA) += depca.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_LANCE) += lance.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
index 2ea221ed4777f01527a81d08d299dcf44a3b6b8f..de774d419144c1fb86ea558b087a627f9f04a6dc 100644 (file)
@@ -437,8 +437,8 @@ static int au1000_mii_probe(struct net_device *dev)
        /* now we are supposed to have a proper phydev, to attach to... */
        BUG_ON(phydev->attached_dev);
 
-       phydev = phy_connect(dev, dev_name(&phydev->dev), &au1000_adjust_link,
-                       0, PHY_INTERFACE_MODE_MII);
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
+                            &au1000_adjust_link, PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
                netdev_err(dev, "Could not attach to PHY\n");
@@ -587,10 +587,10 @@ au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct au1000_private *aup = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       info->fw_version[0] = '\0';
-       sprintf(info->bus_info, "%s %d", DRV_NAME, aup->mac_id);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME,
+                aup->mac_id);
        info->regdump_len = 0;
 }
 
diff --git a/drivers/net/ethernet/amd/depca.c b/drivers/net/ethernet/amd/depca.c
deleted file mode 100644 (file)
index 34a4853..0000000
+++ /dev/null
@@ -1,1910 +0,0 @@
-/*  depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
-
-    Written 1994, 1995 by David C. Davies.
-
-
-                      Copyright 1994 David C. Davies
-                                  and
-                        United States Government
-        (as represented by the Director, National Security Agency).
-
-               Copyright 1995  Digital Equipment Corporation.
-
-
-    This software may be used and distributed according to the terms of
-    the GNU General Public License, incorporated herein by reference.
-
-    This driver is written for the Digital Equipment Corporation series
-    of DEPCA and EtherWORKS ethernet cards:
-
-        DEPCA       (the original)
-       DE100
-       DE101
-       DE200 Turbo
-       DE201 Turbo
-       DE202 Turbo (TP BNC)
-       DE210
-       DE422       (EISA)
-
-    The  driver has been tested on DE100, DE200 and DE202 cards  in  a
-    relatively busy network. The DE422 has been tested a little.
-
-    This  driver will NOT work   for the DE203,  DE204  and DE205 series  of
-    cards,  since they have  a  new custom ASIC in   place of the AMD  LANCE
-    chip.  See the 'ewrk3.c'   driver in the  Linux  source tree for running
-    those cards.
-
-    I have benchmarked the driver with a  DE100 at 595kB/s to (542kB/s from)
-    a DECstation 5000/200.
-
-    The author may be reached at davies@maniac.ultranet.com
-
-    =========================================================================
-
-    The  driver was originally based  on   the 'lance.c' driver from  Donald
-    Becker   which  is included with  the  standard  driver distribution for
-    linux.  V0.4  is  a complete  re-write  with only  the kernel  interface
-    remaining from the original code.
-
-    1) Lance.c code in /linux/drivers/net/
-    2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
-       AMD, 1992 [(800) 222-9323].
-    3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
-       AMD, Pub. #17881, May 1993.
-    4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
-       AMD, Pub. #16907, May 1992
-    5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
-       Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
-    6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
-       Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
-    7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
-       Digital Equipment Corporation, 1989
-    8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
-       Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
-
-
-    Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
-    driver.
-
-    The original DEPCA  card requires that the  ethernet ROM address counter
-    be enabled to count and has an 8 bit NICSR.  The ROM counter enabling is
-    only  done when a  0x08 is read as the  first address octet (to minimise
-    the chances  of writing over some  other hardware's  I/O register).  The
-    NICSR accesses   have been changed  to  byte accesses  for all the cards
-    supported by this driver, since there is only one  useful bit in the MSB
-    (remote boot timeout) and it  is not used.  Also, there  is a maximum of
-    only 48kB network  RAM for this  card.  My thanks  to Torbjorn Lindh for
-    help debugging all this (and holding my feet to  the fire until I got it
-    right).
-
-    The DE200  series  boards have  on-board 64kB  RAM for  use  as a shared
-    memory network  buffer. Only the DE100  cards make use  of a  2kB buffer
-    mode which has not  been implemented in  this driver (only the 32kB  and
-    64kB modes are supported [16kB/48kB for the original DEPCA]).
-
-    At the most only 2 DEPCA cards can  be supported on  the ISA bus because
-    there is only provision  for two I/O base addresses  on each card (0x300
-    and 0x200). The I/O address is detected by searching for a byte sequence
-    in the Ethernet station address PROM at the expected I/O address for the
-    Ethernet  PROM.   The shared memory  base   address  is 'autoprobed'  by
-    looking  for the self  test PROM  and detecting the  card name.   When a
-    second  DEPCA is  detected,  information  is   placed in the   base_addr
-    variable of the  next device structure (which  is created if necessary),
-    thus  enabling ethif_probe  initialization  for the device.  More than 2
-    EISA cards can  be  supported, but  care will  be  needed assigning  the
-    shared memory to ensure that each slot has the  correct IRQ, I/O address
-    and shared memory address assigned.
-
-    ************************************************************************
-
-    NOTE: If you are using two  ISA DEPCAs, it is  important that you assign
-    the base memory addresses correctly.   The  driver autoprobes I/O  0x300
-    then 0x200.  The  base memory address for  the first device must be less
-    than that of the second so that the auto probe will correctly assign the
-    I/O and memory addresses on the same card.  I can't think of a way to do
-    this unambiguously at the moment, since there is nothing on the cards to
-    tie I/O and memory information together.
-
-    I am unable  to  test  2 cards   together for now,    so this  code   is
-    unchecked. All reports, good or bad, are welcome.
-
-    ************************************************************************
-
-    The board IRQ   setting must be  at an  unused IRQ which  is auto-probed
-    using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are
-    {2,3,4,5,7}, whereas the  DE200 is at {5,9,10,11,15}.  Note that IRQ2 is
-    really IRQ9 in machines with 16 IRQ lines.
-
-    No 16MB memory  limitation should exist with this  driver as DMA is  not
-    used and the common memory area is in low memory on the network card (my
-    current system has 20MB and I've not had problems yet).
-
-    The ability to load this driver as a loadable module has been added. To
-    utilise this ability, you have to do <8 things:
-
-    0) have a copy of the loadable modules code installed on your system.
-    1) copy depca.c from the  /linux/drivers/net directory to your favourite
-    temporary directory.
-    2) if you wish, edit the  source code near  line 1530 to reflect the I/O
-    address and IRQ you're using (see also 5).
-    3) compile  depca.c, but include -DMODULE in  the command line to ensure
-    that the correct bits are compiled (see end of source code).
-    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
-    kernel with the depca configuration turned off and reboot.
-    5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100]
-       [Alan Cox: Changed the code to allow command line irq/io assignments]
-       [Dave Davies: Changed the code to allow command line mem/name
-                                                                assignments]
-    6) run the net startup bits for your eth?? interface manually
-    (usually /etc/rc.inet[12] at boot time).
-    7) enjoy!
-
-    Note that autoprobing is not allowed in loadable modules - the system is
-    already up and running and you're messing with interrupts.
-
-    To unload a module, turn off the associated interface
-    'ifconfig eth?? down' then 'rmmod depca'.
-
-    To assign a base memory address for the shared memory  when running as a
-    loadable module, see 5 above.  To include the adapter  name (if you have
-    no PROM  but know the card name)  also see 5  above. Note that this last
-    option  will not work  with kernel  built-in  depca's.
-
-    The shared memory assignment for a loadable module  makes sense to avoid
-    the 'memory autoprobe' picking the wrong shared memory  (for the case of
-    2 depca's in a PC).
-
-    ************************************************************************
-    Support for MCA EtherWORKS cards added 11-3-98. (MCA since deleted)
-    Verified to work with up to 2 DE212 cards in a system (although not
-      fully stress-tested).
-
-    Revision History
-    ----------------
-
-    Version   Date        Description
-
-      0.1     25-jan-94   Initial writing.
-      0.2     27-jan-94   Added LANCE TX hardware buffer chaining.
-      0.3      1-feb-94   Added multiple DEPCA support.
-      0.31     4-feb-94   Added DE202 recognition.
-      0.32    19-feb-94   Tidy up. Improve multi-DEPCA support.
-      0.33    25-feb-94   Fix DEPCA ethernet ROM counter enable.
-                          Add jabber packet fix from murf@perftech.com
-                         and becker@super.org
-      0.34     7-mar-94   Fix DEPCA max network memory RAM & NICSR access.
-      0.35     8-mar-94   Added DE201 recognition. Tidied up.
-      0.351   30-apr-94   Added EISA support. Added DE422 recognition.
-      0.36    16-may-94   DE422 fix released.
-      0.37    22-jul-94   Added MODULE support
-      0.38    15-aug-94   Added DBR ROM switch in depca_close().
-                          Multi DEPCA bug fix.
-      0.38axp 15-sep-94   Special version for Alpha AXP Linux V1.0.
-      0.381   12-dec-94   Added DE101 recognition, fix multicast bug.
-      0.382    9-feb-95   Fix recognition bug reported by <bkm@star.rl.ac.uk>.
-      0.383   22-feb-95   Fix for conflict with VESA SCSI reported by
-                          <stromain@alf.dec.com>
-      0.384   17-mar-95   Fix a ring full bug reported by <bkm@star.rl.ac.uk>
-      0.385    3-apr-95   Fix a recognition bug reported by
-                                                <ryan.niemi@lastfrontier.com>
-      0.386   21-apr-95   Fix the last fix...sorry, must be galloping senility
-      0.40    25-May-95   Rewrite for portability & updated.
-                          ALPHA support from <jestabro@amt.tay1.dec.com>
-      0.41    26-Jun-95   Added verify_area() calls in depca_ioctl() from
-                          suggestion by <heiko@colossus.escape.de>
-      0.42    27-Dec-95   Add 'mem' shared memory assignment for loadable
-                          modules.
-                          Add 'adapter_name' for loadable modules when no PROM.
-                         Both above from a suggestion by
-                         <pchen@woodruffs121.residence.gatech.edu>.
-                         Add new multicasting code.
-      0.421   22-Apr-96          Fix alloc_device() bug <jari@markkus2.fimr.fi>
-      0.422   29-Apr-96          Fix depca_hw_init() bug <jari@markkus2.fimr.fi>
-      0.423    7-Jun-96   Fix module load bug <kmg@barco.be>
-      0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
-      0.44     1-Sep-97   Fix *_probe() to test check_region() first - bug
-                           reported by <mmogilvi@elbert.uccs.edu>
-      0.45     3-Nov-98   Added support for MCA EtherWORKS (DE210/DE212) cards
-                           by <tymm@computer.org>
-      0.451    5-Nov-98   Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
-      0.5     14-Nov-98   Re-spin for 2.1.x kernels.
-      0.51    27-Jun-99   Correct received packet length for CRC from
-                           report by <worm@dkik.dk>
-      0.52    16-Oct-00   Fixes for 2.3 io memory accesses
-                          Fix show-stopper (ints left masked) in depca_interrupt
-                          by <peterd@pnd-pc.demon.co.uk>
-      0.53    12-Jan-01          Release resources on failure, bss tidbits
-                          by acme@conectiva.com.br
-      0.54    08-Nov-01          use library crc32 functions
-                          by Matt_Domsch@dell.com
-      0.55    01-Mar-03   Use EISA/sysfs framework <maz@wild-wind.fr.eu.org>
-
-    =========================================================================
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#ifdef CONFIG_EISA
-#include <linux/eisa.h>
-#endif
-
-#include "depca.h"
-
-static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
-
-#ifdef DEPCA_DEBUG
-static int depca_debug = DEPCA_DEBUG;
-#else
-static int depca_debug = 1;
-#endif
-
-#define DEPCA_NDA 0xffe0       /* No Device Address */
-
-#define TX_TIMEOUT (1*HZ)
-
-/*
-** Ethernet PROM defines
-*/
-#define PROBE_LENGTH    32
-#define ETH_PROM_SIG    0xAA5500FFUL
-
-/*
-** Set the number of Tx and Rx buffers. Ensure that the memory requested
-** here is <= to the amount of shared memory set up by the board switches.
-** The number of descriptors MUST BE A POWER OF 2.
-**
-** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
-*/
-#define NUM_RX_DESC     8      /* Number of RX descriptors */
-#define NUM_TX_DESC     8      /* Number of TX descriptors */
-#define RX_BUFF_SZ     1536    /* Buffer size for each Rx buffer */
-#define TX_BUFF_SZ     1536    /* Buffer size for each Tx buffer */
-
-/*
-** EISA bus defines
-*/
-#define DEPCA_EISA_IO_PORTS 0x0c00     /* I/O port base address, slot 0 */
-
-/*
-** ISA Bus defines
-*/
-#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
-#define DEPCA_TOTAL_SIZE 0x10
-
-static struct {
-       u_long iobase;
-       struct platform_device *device;
-} depca_io_ports[] = {
-       { 0x300, NULL },
-       { 0x200, NULL },
-       { 0    , NULL },
-};
-
-/*
-** Name <-> Adapter mapping
-*/
-#define DEPCA_SIGNATURE {"DEPCA",\
-                        "DE100","DE101",\
-                         "DE200","DE201","DE202",\
-                        "DE210","DE212",\
-                         "DE422",\
-                         ""}
-
-static char* __initdata depca_signature[] = DEPCA_SIGNATURE;
-
-enum depca_type {
-       DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
-};
-
-static char depca_string[] = "depca";
-
-static int depca_device_remove (struct device *device);
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id depca_eisa_ids[] = {
-       { "DEC4220", de422 },
-       { "" }
-};
-MODULE_DEVICE_TABLE(eisa, depca_eisa_ids);
-
-static int depca_eisa_probe  (struct device *device);
-
-static struct eisa_driver depca_eisa_driver = {
-       .id_table = depca_eisa_ids,
-       .driver   = {
-               .name    = depca_string,
-               .probe   = depca_eisa_probe,
-               .remove  = depca_device_remove
-       }
-};
-#endif
-
-static int depca_isa_probe (struct platform_device *);
-
-static int depca_isa_remove(struct platform_device *pdev)
-{
-       return depca_device_remove(&pdev->dev);
-}
-
-static struct platform_driver depca_isa_driver = {
-       .probe  = depca_isa_probe,
-       .remove = depca_isa_remove,
-       .driver = {
-               .name   = depca_string,
-       },
-};
-
-/*
-** Miscellaneous info...
-*/
-#define DEPCA_STRLEN 16
-
-/*
-** Memory Alignment. Each descriptor is 4 longwords long. To force a
-** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
-** DESC_ALIGN. DEPCA_ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
-*/
-#define DEPCA_ALIGN4      ((u_long)4 - 1)      /* 1 longword align */
-#define DEPCA_ALIGN8      ((u_long)8 - 1)      /* 2 longword (quadword) align */
-#define DEPCA_ALIGN         DEPCA_ALIGN8       /* Keep the LANCE happy... */
-
-/*
-** The DEPCA Rx and Tx ring descriptors.
-*/
-struct depca_rx_desc {
-       volatile s32 base;
-       s16 buf_length;         /* This length is negative 2's complement! */
-       s16 msg_length;         /* This length is "normal". */
-};
-
-struct depca_tx_desc {
-       volatile s32 base;
-       s16 length;             /* This length is negative 2's complement! */
-       s16 misc;               /* Errors and TDR info */
-};
-
-#define LA_MASK 0x0000ffff     /* LANCE address mask for mapping network RAM
-                                  to LANCE memory address space */
-
-/*
-** The Lance initialization block, described in databook, in common memory.
-*/
-struct depca_init {
-       u16 mode;               /* Mode register */
-       u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */
-       u8 mcast_table[8];      /* Multicast Hash Table. */
-       u32 rx_ring;            /* Rx ring base pointer & ring length */
-       u32 tx_ring;            /* Tx ring base pointer & ring length */
-};
-
-#define DEPCA_PKT_STAT_SZ 16
-#define DEPCA_PKT_BIN_SZ  128  /* Should be >=100 unless you
-                                  increase DEPCA_PKT_STAT_SZ */
-struct depca_private {
-       char adapter_name[DEPCA_STRLEN];        /* /proc/ioports string                  */
-       enum depca_type adapter;                /* Adapter type */
-       enum {
-                DEPCA_BUS_ISA = 1,
-                DEPCA_BUS_EISA,
-        } depca_bus;           /* type of bus */
-       struct depca_init init_block;   /* Shadow Initialization block            */
-/* CPU address space fields */
-       struct depca_rx_desc __iomem *rx_ring;  /* Pointer to start of RX descriptor ring */
-       struct depca_tx_desc __iomem *tx_ring;  /* Pointer to start of TX descriptor ring */
-       void __iomem *rx_buff[NUM_RX_DESC];     /* CPU virt address of sh'd memory buffs  */
-       void __iomem *tx_buff[NUM_TX_DESC];     /* CPU virt address of sh'd memory buffs  */
-       void __iomem *sh_mem;   /* CPU mapped virt address of device RAM  */
-       u_long mem_start;       /* Bus address of device RAM (before remap) */
-       u_long mem_len;         /* device memory size */
-/* Device address space fields */
-       u_long device_ram_start;        /* Start of RAM in device addr space      */
-/* Offsets used in both address spaces */
-       u_long rx_ring_offset;  /* Offset from start of RAM to rx_ring    */
-       u_long tx_ring_offset;  /* Offset from start of RAM to tx_ring    */
-       u_long buffs_offset;    /* LANCE Rx and Tx buffers start address. */
-/* Kernel-only (not device) fields */
-       int rx_new, tx_new;     /* The next free ring entry               */
-       int rx_old, tx_old;     /* The ring entries to be free()ed.       */
-       spinlock_t lock;
-       struct {                /* Private stats counters                 */
-               u32 bins[DEPCA_PKT_STAT_SZ];
-               u32 unicast;
-               u32 multicast;
-               u32 broadcast;
-               u32 excessive_collisions;
-               u32 tx_underruns;
-               u32 excessive_underruns;
-       } pktStats;
-       int txRingMask;         /* TX ring mask                           */
-       int rxRingMask;         /* RX ring mask                           */
-       s32 rx_rlen;            /* log2(rxRingMask+1) for the descriptors */
-       s32 tx_rlen;            /* log2(txRingMask+1) for the descriptors */
-};
-
-/*
-** The transmit ring full condition is described by the tx_old and tx_new
-** pointers by:
-**    tx_old            = tx_new    Empty ring
-**    tx_old            = tx_new+1  Full ring
-**    tx_old+txRingMask = tx_new    Full ring  (wrapped condition)
-*/
-#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
-                        lp->tx_old+lp->txRingMask-lp->tx_new:\
-                         lp->tx_old               -lp->tx_new-1)
-
-/*
-** Public Functions
-*/
-static int depca_open(struct net_device *dev);
-static netdev_tx_t depca_start_xmit(struct sk_buff *skb,
-                                   struct net_device *dev);
-static irqreturn_t depca_interrupt(int irq, void *dev_id);
-static int depca_close(struct net_device *dev);
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void depca_tx_timeout(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-/*
-** Private functions
-*/
-static void depca_init_ring(struct net_device *dev);
-static int depca_rx(struct net_device *dev);
-static int depca_tx(struct net_device *dev);
-
-static void LoadCSRs(struct net_device *dev);
-static int InitRestartDepca(struct net_device *dev);
-static int DepcaSignature(char *name, u_long paddr);
-static int DevicePresent(u_long ioaddr);
-static int get_hw_addr(struct net_device *dev);
-static void SetMulticastFilter(struct net_device *dev);
-static int load_packet(struct net_device *dev, struct sk_buff *skb);
-static void depca_dbg_open(struct net_device *dev);
-
-static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
-static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
-static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
-static u_char *depca_irq;
-
-static int irq;
-static int io;
-static char *adapter_name;
-static int mem;                        /* For loadable module assignment
-                                  use insmod mem=0x????? .... */
-module_param (irq, int, 0);
-module_param (io, int, 0);
-module_param (adapter_name, charp, 0);
-module_param (mem, int, 0);
-MODULE_PARM_DESC(irq, "DEPCA IRQ number");
-MODULE_PARM_DESC(io, "DEPCA I/O base address");
-MODULE_PARM_DESC(adapter_name, "DEPCA adapter name");
-MODULE_PARM_DESC(mem, "DEPCA shared memory address");
-MODULE_LICENSE("GPL");
-
-/*
-** Miscellaneous defines...
-*/
-#define STOP_DEPCA \
-    outw(CSR0, DEPCA_ADDR);\
-    outw(STOP, DEPCA_DATA)
-
-static const struct net_device_ops depca_netdev_ops = {
-       .ndo_open               = depca_open,
-       .ndo_start_xmit         = depca_start_xmit,
-       .ndo_stop               = depca_close,
-       .ndo_set_rx_mode        = set_multicast_list,
-       .ndo_do_ioctl           = depca_ioctl,
-       .ndo_tx_timeout         = depca_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init depca_hw_init (struct net_device *dev, struct device *device)
-{
-       struct depca_private *lp;
-       int i, j, offset, netRAM, mem_len, status = 0;
-       s16 nicsr;
-       u_long ioaddr;
-       u_long mem_start;
-
-       /*
-        * We are now supposed to enter this function with the
-        * following fields filled with proper values :
-        *
-        * dev->base_addr
-        * lp->mem_start
-        * lp->depca_bus
-        * lp->adapter
-        *
-        * dev->irq can be set if known from device configuration (on
-        * MCA or EISA) or module option. Otherwise, it will be auto
-        * detected.
-        */
-
-       ioaddr = dev->base_addr;
-
-       STOP_DEPCA;
-
-       nicsr = inb(DEPCA_NICSR);
-       nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
-       outb(nicsr, DEPCA_NICSR);
-
-       if (inw(DEPCA_DATA) != STOP) {
-               return -ENXIO;
-       }
-
-       lp = netdev_priv(dev);
-       mem_start = lp->mem_start;
-
-       if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown)
-               return -ENXIO;
-
-       printk("%s: %s at 0x%04lx",
-              dev_name(device), depca_signature[lp->adapter], ioaddr);
-
-       switch (lp->depca_bus) {
-#ifdef CONFIG_EISA
-       case DEPCA_BUS_EISA:
-               printk(" (EISA slot %d)", to_eisa_device(device)->slot);
-               break;
-#endif
-
-       case DEPCA_BUS_ISA:
-               break;
-
-       default:
-               printk("Unknown DEPCA bus %d\n", lp->depca_bus);
-               return -ENXIO;
-       }
-
-       printk(", h/w address ");
-       status = get_hw_addr(dev);
-       printk("%pM", dev->dev_addr);
-       if (status != 0) {
-               printk("      which has an Ethernet PROM CRC error.\n");
-               return -ENXIO;
-       }
-
-       /* Set up the maximum amount of network RAM(kB) */
-       netRAM = ((lp->adapter != DEPCA) ? 64 : 48);
-       if ((nicsr & _128KB) && (lp->adapter == de422))
-               netRAM = 128;
-
-       /* Shared Memory Base Address */
-       if (nicsr & BUF) {
-               nicsr &= ~BS;   /* DEPCA RAM in top 32k */
-               netRAM -= 32;
-               mem_start += 0x8000;
-       }
-
-       if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
-           > (netRAM << 10)) {
-               printk(",\n       requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
-               return -ENXIO;
-       }
-
-       printk(",\n      has %dkB RAM at 0x%.5lx", netRAM, mem_start);
-
-       /* Enable the shadow RAM. */
-       if (lp->adapter != DEPCA) {
-               nicsr |= SHE;
-               outb(nicsr, DEPCA_NICSR);
-       }
-
-       spin_lock_init(&lp->lock);
-       sprintf(lp->adapter_name, "%s (%s)",
-               depca_signature[lp->adapter], dev_name(device));
-       status = -EBUSY;
-
-       /* Initialisation Block */
-       if (!request_mem_region (mem_start, mem_len, lp->adapter_name)) {
-               printk(KERN_ERR "depca: cannot request ISA memory, aborting\n");
-               goto out_priv;
-       }
-
-       status = -EIO;
-       lp->sh_mem = ioremap(mem_start, mem_len);
-       if (lp->sh_mem == NULL) {
-               printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n");
-               goto out1;
-       }
-
-       lp->mem_start = mem_start;
-       lp->mem_len   = mem_len;
-       lp->device_ram_start = mem_start & LA_MASK;
-
-       offset = 0;
-       offset += sizeof(struct depca_init);
-
-       /* Tx & Rx descriptors (aligned to a quadword boundary) */
-       offset = (offset + DEPCA_ALIGN) & ~DEPCA_ALIGN;
-       lp->rx_ring = lp->sh_mem + offset;
-       lp->rx_ring_offset = offset;
-
-       offset += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
-       lp->tx_ring = lp->sh_mem + offset;
-       lp->tx_ring_offset = offset;
-
-       offset += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
-
-       lp->buffs_offset = offset;
-
-       /* Finish initialising the ring information. */
-       lp->rxRingMask = NUM_RX_DESC - 1;
-       lp->txRingMask = NUM_TX_DESC - 1;
-
-       /* Calculate Tx/Rx RLEN size for the descriptors. */
-       for (i = 0, j = lp->rxRingMask; j > 0; i++) {
-               j >>= 1;
-       }
-       lp->rx_rlen = (s32) (i << 29);
-       for (i = 0, j = lp->txRingMask; j > 0; i++) {
-               j >>= 1;
-       }
-       lp->tx_rlen = (s32) (i << 29);
-
-       /* Load the initialisation block */
-       depca_init_ring(dev);
-
-       /* Initialise the control and status registers */
-       LoadCSRs(dev);
-
-       /* Enable DEPCA board interrupts for autoprobing */
-       nicsr = ((nicsr & ~IM) | IEN);
-       outb(nicsr, DEPCA_NICSR);
-
-       /* To auto-IRQ we enable the initialization-done and DMA err,
-          interrupts. For now we will always get a DMA error. */
-       if (dev->irq < 2) {
-               unsigned char irqnum;
-               unsigned long irq_mask, delay;
-
-               irq_mask = probe_irq_on();
-
-               /* Assign the correct irq list */
-               switch (lp->adapter) {
-               case DEPCA:
-               case de100:
-               case de101:
-                       depca_irq = de1xx_irq;
-                       break;
-               case de200:
-               case de201:
-               case de202:
-               case de210:
-               case de212:
-                       depca_irq = de2xx_irq;
-                       break;
-               case de422:
-                       depca_irq = de422_irq;
-                       break;
-
-               default:
-                       break;  /* Not reached */
-               }
-
-               /* Trigger an initialization just for the interrupt. */
-               outw(INEA | INIT, DEPCA_DATA);
-
-               delay = jiffies + HZ/50;
-               while (time_before(jiffies, delay))
-                       yield();
-
-               irqnum = probe_irq_off(irq_mask);
-
-               status = -ENXIO;
-               if (!irqnum) {
-                       printk(" and failed to detect IRQ line.\n");
-                       goto out2;
-               } else {
-                       for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++)
-                               if (irqnum == depca_irq[i]) {
-                                       dev->irq = irqnum;
-                                       printk(" and uses IRQ%d.\n", dev->irq);
-                               }
-
-                       if (!dev->irq) {
-                               printk(" but incorrect IRQ line detected.\n");
-                               goto out2;
-                       }
-               }
-       } else {
-               printk(" and assigned IRQ%d.\n", dev->irq);
-       }
-
-       if (depca_debug > 1) {
-               printk(version);
-       }
-
-       /* The DEPCA-specific entries in the device structure. */
-       dev->netdev_ops = &depca_netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-
-       dev->mem_start = 0;
-
-       dev_set_drvdata(device, dev);
-       SET_NETDEV_DEV (dev, device);
-
-       status = register_netdev(dev);
-       if (status == 0)
-               return 0;
-out2:
-       iounmap(lp->sh_mem);
-out1:
-       release_mem_region (mem_start, mem_len);
-out_priv:
-       return status;
-}
-
-
-static int depca_open(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       u_long ioaddr = dev->base_addr;
-       s16 nicsr;
-       int status = 0;
-
-       STOP_DEPCA;
-       nicsr = inb(DEPCA_NICSR);
-
-       /* Make sure the shadow RAM is enabled */
-       if (lp->adapter != DEPCA) {
-               nicsr |= SHE;
-               outb(nicsr, DEPCA_NICSR);
-       }
-
-       /* Re-initialize the DEPCA... */
-       depca_init_ring(dev);
-       LoadCSRs(dev);
-
-       depca_dbg_open(dev);
-
-       if (request_irq(dev->irq, depca_interrupt, 0, lp->adapter_name, dev)) {
-               printk("depca_open(): Requested IRQ%d is busy\n", dev->irq);
-               status = -EAGAIN;
-       } else {
-
-               /* Enable DEPCA board interrupts and turn off LED */
-               nicsr = ((nicsr & ~IM & ~LED) | IEN);
-               outb(nicsr, DEPCA_NICSR);
-               outw(CSR0, DEPCA_ADDR);
-
-               netif_start_queue(dev);
-
-               status = InitRestartDepca(dev);
-
-               if (depca_debug > 1) {
-                       printk("CSR0: 0x%4.4x\n", inw(DEPCA_DATA));
-                       printk("nicsr: 0x%02x\n", inb(DEPCA_NICSR));
-               }
-       }
-       return status;
-}
-
-/* Initialize the lance Rx and Tx descriptor rings. */
-static void depca_init_ring(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       u_int i;
-       u_long offset;
-
-       /* Lock out other processes whilst setting up the hardware */
-       netif_stop_queue(dev);
-
-       lp->rx_new = lp->tx_new = 0;
-       lp->rx_old = lp->tx_old = 0;
-
-       /* Initialize the base address and length of each buffer in the ring */
-       for (i = 0; i <= lp->rxRingMask; i++) {
-               offset = lp->buffs_offset + i * RX_BUFF_SZ;
-               writel((lp->device_ram_start + offset) | R_OWN, &lp->rx_ring[i].base);
-               writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
-               lp->rx_buff[i] = lp->sh_mem + offset;
-       }
-
-       for (i = 0; i <= lp->txRingMask; i++) {
-               offset = lp->buffs_offset + (i + lp->rxRingMask + 1) * TX_BUFF_SZ;
-               writel((lp->device_ram_start + offset) & 0x00ffffff, &lp->tx_ring[i].base);
-               lp->tx_buff[i] = lp->sh_mem + offset;
-       }
-
-       /* Set up the initialization block */
-       lp->init_block.rx_ring = (lp->device_ram_start + lp->rx_ring_offset) | lp->rx_rlen;
-       lp->init_block.tx_ring = (lp->device_ram_start + lp->tx_ring_offset) | lp->tx_rlen;
-
-       SetMulticastFilter(dev);
-
-       for (i = 0; i < ETH_ALEN; i++) {
-               lp->init_block.phys_addr[i] = dev->dev_addr[i];
-       }
-
-       lp->init_block.mode = 0x0000;   /* Enable the Tx and Rx */
-}
-
-
-static void depca_tx_timeout(struct net_device *dev)
-{
-       u_long ioaddr = dev->base_addr;
-
-       printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA));
-
-       STOP_DEPCA;
-       depca_init_ring(dev);
-       LoadCSRs(dev);
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue(dev);
-       InitRestartDepca(dev);
-}
-
-
-/*
-** Writes a socket buffer to TX descriptor ring and starts transmission
-*/
-static netdev_tx_t depca_start_xmit(struct sk_buff *skb,
-                                   struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       u_long ioaddr = dev->base_addr;
-       int status = 0;
-
-       /* Transmitter timeout, serious problems. */
-       if (skb->len < 1)
-               goto out;
-
-       if (skb_padto(skb, ETH_ZLEN))
-               goto out;
-
-       netif_stop_queue(dev);
-
-       if (TX_BUFFS_AVAIL) {   /* Fill in a Tx ring entry */
-               status = load_packet(dev, skb);
-
-               if (!status) {
-                       /* Trigger an immediate send demand. */
-                       outw(CSR0, DEPCA_ADDR);
-                       outw(INEA | TDMD, DEPCA_DATA);
-
-                       dev_kfree_skb(skb);
-               }
-               if (TX_BUFFS_AVAIL)
-                       netif_start_queue(dev);
-       } else
-               status = NETDEV_TX_LOCKED;
-
-      out:
-       return status;
-}
-
-/*
-** The DEPCA interrupt handler.
-*/
-static irqreturn_t depca_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct depca_private *lp;
-       s16 csr0, nicsr;
-       u_long ioaddr;
-
-       if (dev == NULL) {
-               printk("depca_interrupt(): irq %d for unknown device.\n", irq);
-               return IRQ_NONE;
-       }
-
-       lp = netdev_priv(dev);
-       ioaddr = dev->base_addr;
-
-       spin_lock(&lp->lock);
-
-       /* mask the DEPCA board interrupts and turn on the LED */
-       nicsr = inb(DEPCA_NICSR);
-       nicsr |= (IM | LED);
-       outb(nicsr, DEPCA_NICSR);
-
-       outw(CSR0, DEPCA_ADDR);
-       csr0 = inw(DEPCA_DATA);
-
-       /* Acknowledge all of the current interrupt sources ASAP. */
-       outw(csr0 & INTE, DEPCA_DATA);
-
-       if (csr0 & RINT)        /* Rx interrupt (packet arrived) */
-               depca_rx(dev);
-
-       if (csr0 & TINT)        /* Tx interrupt (packet sent) */
-               depca_tx(dev);
-
-       /* Any resources available? */
-       if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
-               netif_wake_queue(dev);
-       }
-
-       /* Unmask the DEPCA board interrupts and turn off the LED */
-       nicsr = (nicsr & ~IM & ~LED);
-       outb(nicsr, DEPCA_NICSR);
-
-       spin_unlock(&lp->lock);
-       return IRQ_HANDLED;
-}
-
-/* Called with lp->lock held */
-static int depca_rx(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       int i, entry;
-       s32 status;
-
-       for (entry = lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry = lp->rx_new) {
-               status = readl(&lp->rx_ring[entry].base) >> 16;
-               if (status & R_STP) {   /* Remember start of frame */
-                       lp->rx_old = entry;
-               }
-               if (status & R_ENP) {   /* Valid frame status */
-                       if (status & R_ERR) {   /* There was an error. */
-                               dev->stats.rx_errors++; /* Update the error stats. */
-                               if (status & R_FRAM)
-                                       dev->stats.rx_frame_errors++;
-                               if (status & R_OFLO)
-                                       dev->stats.rx_over_errors++;
-                               if (status & R_CRC)
-                                       dev->stats.rx_crc_errors++;
-                               if (status & R_BUFF)
-                                       dev->stats.rx_fifo_errors++;
-                       } else {
-                               short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
-                               struct sk_buff *skb;
-
-                               skb = netdev_alloc_skb(dev, pkt_len + 2);
-                               if (skb != NULL) {
-                                       unsigned char *buf;
-                                       skb_reserve(skb, 2);    /* 16 byte align the IP header */
-                                       buf = skb_put(skb, pkt_len);
-                                       if (entry < lp->rx_old) {       /* Wrapped buffer */
-                                               len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
-                                               memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
-                                               memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len - len);
-                                       } else {        /* Linear buffer */
-                                               memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
-                                       }
-
-                                       /*
-                                          ** Notify the upper protocol layers that there is another
-                                          ** packet to handle
-                                        */
-                                       skb->protocol = eth_type_trans(skb, dev);
-                                       netif_rx(skb);
-
-                                       /*
-                                          ** Update stats
-                                        */
-                                       dev->stats.rx_packets++;
-                                       dev->stats.rx_bytes += pkt_len;
-                                       for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
-                                               if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
-                                                       lp->pktStats.bins[i]++;
-                                                       i = DEPCA_PKT_STAT_SZ;
-                                               }
-                                       }
-                                       if (is_multicast_ether_addr(buf)) {
-                                               if (is_broadcast_ether_addr(buf)) {
-                                                       lp->pktStats.broadcast++;
-                                               } else {
-                                                       lp->pktStats.multicast++;
-                                               }
-                                       } else if (ether_addr_equal(buf,
-                                                                   dev->dev_addr)) {
-                                               lp->pktStats.unicast++;
-                                       }
-
-                                       lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
-                                       if (lp->pktStats.bins[0] == 0) {        /* Reset counters */
-                                               memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats));
-                                       }
-                               } else {
-                                       printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-                                       dev->stats.rx_dropped++;        /* Really, deferred. */
-                                       break;
-                               }
-                       }
-                       /* Change buffer ownership for this last frame, back to the adapter */
-                       for (; lp->rx_old != entry; lp->rx_old = (lp->rx_old + 1) & lp->rxRingMask) {
-                               writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
-                       }
-                       writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
-               }
-
-               /*
-                  ** Update entry information
-                */
-               lp->rx_new = (lp->rx_new + 1) & lp->rxRingMask;
-       }
-
-       return 0;
-}
-
-/*
-** Buffer sent - check for buffer errors.
-** Called with lp->lock held
-*/
-static int depca_tx(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       int entry;
-       s32 status;
-       u_long ioaddr = dev->base_addr;
-
-       for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
-               status = readl(&lp->tx_ring[entry].base) >> 16;
-
-               if (status < 0) {       /* Packet not yet sent! */
-                       break;
-               } else if (status & T_ERR) {    /* An error occurred. */
-                       status = readl(&lp->tx_ring[entry].misc);
-                       dev->stats.tx_errors++;
-                       if (status & TMD3_RTRY)
-                               dev->stats.tx_aborted_errors++;
-                       if (status & TMD3_LCAR)
-                               dev->stats.tx_carrier_errors++;
-                       if (status & TMD3_LCOL)
-                               dev->stats.tx_window_errors++;
-                       if (status & TMD3_UFLO)
-                               dev->stats.tx_fifo_errors++;
-                       if (status & (TMD3_BUFF | TMD3_UFLO)) {
-                               /* Trigger an immediate send demand. */
-                               outw(CSR0, DEPCA_ADDR);
-                               outw(INEA | TDMD, DEPCA_DATA);
-                       }
-               } else if (status & (T_MORE | T_ONE)) {
-                       dev->stats.collisions++;
-               } else {
-                       dev->stats.tx_packets++;
-               }
-
-               /* Update all the pointers */
-               lp->tx_old = (lp->tx_old + 1) & lp->txRingMask;
-       }
-
-       return 0;
-}
-
-static int depca_close(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       s16 nicsr;
-       u_long ioaddr = dev->base_addr;
-
-       netif_stop_queue(dev);
-
-       outw(CSR0, DEPCA_ADDR);
-
-       if (depca_debug > 1) {
-               printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
-       }
-
-       /*
-          ** We stop the DEPCA here -- it occasionally polls
-          ** memory if we don't.
-        */
-       outw(STOP, DEPCA_DATA);
-
-       /*
-          ** Give back the ROM in case the user wants to go to DOS
-        */
-       if (lp->adapter != DEPCA) {
-               nicsr = inb(DEPCA_NICSR);
-               nicsr &= ~SHE;
-               outb(nicsr, DEPCA_NICSR);
-       }
-
-       /*
-          ** Free the associated irq
-        */
-       free_irq(dev->irq, dev);
-       return 0;
-}
-
-static void LoadCSRs(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       u_long ioaddr = dev->base_addr;
-
-       outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
-       outw((u16) lp->device_ram_start, DEPCA_DATA);
-       outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
-       outw((u16) (lp->device_ram_start >> 16), DEPCA_DATA);
-       outw(CSR3, DEPCA_ADDR); /* ALE control */
-       outw(ACON, DEPCA_DATA);
-
-       outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */
-}
-
-static int InitRestartDepca(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       u_long ioaddr = dev->base_addr;
-       int i, status = 0;
-
-       /* Copy the shadow init_block to shared memory */
-       memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
-
-       outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
-       outw(INIT, DEPCA_DATA); /* initialize DEPCA */
-
-       /* wait for lance to complete initialisation */
-       for (i = 0; (i < 100) && !(inw(DEPCA_DATA) & IDON); i++);
-
-       if (i != 100) {
-               /* clear IDON by writing a "1", enable interrupts and start lance */
-               outw(IDON | INEA | STRT, DEPCA_DATA);
-               if (depca_debug > 2) {
-                       printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
-               }
-       } else {
-               printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
-               status = -1;
-       }
-
-       return status;
-}
-
-/*
-** Set or clear the multicast filter for this adaptor.
-*/
-static void set_multicast_list(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       u_long ioaddr = dev->base_addr;
-
-       netif_stop_queue(dev);
-       while (lp->tx_old != lp->tx_new);       /* Wait for the ring to empty */
-
-       STOP_DEPCA;     /* Temporarily stop the depca.  */
-       depca_init_ring(dev);   /* Initialize the descriptor rings */
-
-       if (dev->flags & IFF_PROMISC) { /* Set promiscuous mode */
-               lp->init_block.mode |= PROM;
-       } else {
-               SetMulticastFilter(dev);
-               lp->init_block.mode &= ~PROM;   /* Unset promiscuous mode */
-       }
-
-       LoadCSRs(dev);  /* Reload CSR3 */
-       InitRestartDepca(dev);  /* Resume normal operation. */
-       netif_start_queue(dev); /* Unlock the TX ring */
-}
-
-/*
-** Calculate the hash code and update the logical address filter
-** from a list of ethernet multicast addresses.
-** Big endian crc one liner is mine, all mine, ha ha ha ha!
-** LANCE calculates its hash codes big endian.
-*/
-static void SetMulticastFilter(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       struct netdev_hw_addr *ha;
-       int i, j, bit, byte;
-       u16 hashcode;
-       u32 crc;
-
-       if (dev->flags & IFF_ALLMULTI) {        /* Set all multicast bits */
-               for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-                       lp->init_block.mcast_table[i] = (char) 0xff;
-               }
-       } else {
-               for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {   /* Clear the multicast table */
-                       lp->init_block.mcast_table[i] = 0;
-               }
-               /* Add multicast addresses */
-               netdev_for_each_mc_addr(ha, dev) {
-                       crc = ether_crc(ETH_ALEN, ha->addr);
-                       hashcode = (crc & 1);   /* hashcode is 6 LSb of CRC ... */
-                       for (j = 0; j < 5; j++) {       /* ... in reverse order. */
-                               hashcode = (hashcode << 1) | ((crc >>= 1) & 1);
-                       }
-
-                       byte = hashcode >> 3;   /* bit[3-5] -> byte in filter */
-                       bit = 1 << (hashcode & 0x07);   /* bit[0-2] -> bit in byte */
-                       lp->init_block.mcast_table[byte] |= bit;
-               }
-       }
-}
-
-static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
-{
-       int status = 0;
-
-       if (!request_region (ioaddr, DEPCA_TOTAL_SIZE, depca_string)) {
-               status = -EBUSY;
-               goto out;
-       }
-
-       if (DevicePresent(ioaddr)) {
-               status = -ENODEV;
-               goto out_release;
-       }
-
-       if (!(*devp = alloc_etherdev (sizeof (struct depca_private)))) {
-               status = -ENOMEM;
-               goto out_release;
-       }
-
-       return 0;
-
- out_release:
-       release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
-       return status;
-}
-
-/*
-** ISA bus I/O device probe
-*/
-
-static void __init depca_platform_probe (void)
-{
-       int i;
-       struct platform_device *pldev;
-
-       for (i = 0; depca_io_ports[i].iobase; i++) {
-               depca_io_ports[i].device = NULL;
-
-               /* if an address has been specified on the command
-                * line, use it (if valid) */
-               if (io && io != depca_io_ports[i].iobase)
-                       continue;
-
-               pldev = platform_device_alloc(depca_string, i);
-               if (!pldev)
-                       continue;
-
-               pldev->dev.platform_data = (void *) depca_io_ports[i].iobase;
-               depca_io_ports[i].device = pldev;
-
-               if (platform_device_add(pldev)) {
-                       depca_io_ports[i].device = NULL;
-                       pldev->dev.platform_data = NULL;
-                       platform_device_put(pldev);
-                       continue;
-               }
-
-               if (!pldev->dev.driver) {
-               /* The driver was not bound to this device, there was
-                * no hardware at this address. Unregister it, as the
-                * release function will take care of freeing the
-                * allocated structure */
-
-                       depca_io_ports[i].device = NULL;
-                       pldev->dev.platform_data = NULL;
-                       platform_device_unregister (pldev);
-               }
-       }
-}
-
-static enum depca_type __init depca_shmem_probe (ulong *mem_start)
-{
-       u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
-       enum depca_type adapter = unknown;
-       int i;
-
-       for (i = 0; mem_base[i]; i++) {
-               *mem_start = mem ? mem : mem_base[i];
-               adapter = DepcaSignature (adapter_name, *mem_start);
-               if (adapter != unknown)
-                       break;
-       }
-
-       return adapter;
-}
-
-static int depca_isa_probe(struct platform_device *device)
-{
-       struct net_device *dev;
-       struct depca_private *lp;
-       u_long ioaddr, mem_start = 0;
-       enum depca_type adapter = unknown;
-       int status = 0;
-
-       ioaddr = (u_long) device->dev.platform_data;
-
-       if ((status = depca_common_init (ioaddr, &dev)))
-               goto out;
-
-       adapter = depca_shmem_probe (&mem_start);
-
-       if (adapter == unknown) {
-               status = -ENODEV;
-               goto out_free;
-       }
-
-       dev->base_addr = ioaddr;
-       dev->irq = irq;         /* Use whatever value the user gave
-                                * us, and 0 if he didn't. */
-       lp = netdev_priv(dev);
-       lp->depca_bus = DEPCA_BUS_ISA;
-       lp->adapter = adapter;
-       lp->mem_start = mem_start;
-
-       if ((status = depca_hw_init(dev, &device->dev)))
-               goto out_free;
-
-       return 0;
-
- out_free:
-       free_netdev (dev);
-       release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
-       return status;
-}
-
-/*
-** EISA callbacks from sysfs.
-*/
-
-#ifdef CONFIG_EISA
-static int __init depca_eisa_probe (struct device *device)
-{
-       enum depca_type adapter = unknown;
-       struct eisa_device *edev;
-       struct net_device *dev;
-       struct depca_private *lp;
-       u_long ioaddr, mem_start;
-       int status = 0;
-
-       edev = to_eisa_device (device);
-       ioaddr = edev->base_addr + DEPCA_EISA_IO_PORTS;
-
-       if ((status = depca_common_init (ioaddr, &dev)))
-               goto out;
-
-       /* It would have been nice to get card configuration from the
-        * card. Unfortunately, this register is write-only (shares
-        * it's address with the ethernet prom)... As we don't parse
-        * the EISA configuration structures (yet... :-), just rely on
-        * the ISA probing to sort it out... */
-
-       adapter = depca_shmem_probe (&mem_start);
-       if (adapter == unknown) {
-               status = -ENODEV;
-               goto out_free;
-       }
-
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-       lp = netdev_priv(dev);
-       lp->depca_bus = DEPCA_BUS_EISA;
-       lp->adapter = edev->id.driver_data;
-       lp->mem_start = mem_start;
-
-       if ((status = depca_hw_init(dev, device)))
-               goto out_free;
-
-       return 0;
-
- out_free:
-       free_netdev (dev);
-       release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
-       return status;
-}
-#endif
-
-static int depca_device_remove(struct device *device)
-{
-       struct net_device *dev;
-       struct depca_private *lp;
-       int bus;
-
-       dev  = dev_get_drvdata(device);
-       lp   = netdev_priv(dev);
-
-       unregister_netdev (dev);
-       iounmap (lp->sh_mem);
-       release_mem_region (lp->mem_start, lp->mem_len);
-       release_region (dev->base_addr, DEPCA_TOTAL_SIZE);
-       bus = lp->depca_bus;
-       free_netdev (dev);
-
-       return 0;
-}
-
-/*
-** Look for a particular board name in the on-board Remote Diagnostics
-** and Boot (readb) ROM. This will also give us a clue to the network RAM
-** base address.
-*/
-static int __init DepcaSignature(char *name, u_long base_addr)
-{
-       u_int i, j, k;
-       void __iomem *ptr;
-       char tmpstr[16];
-       u_long prom_addr = base_addr + 0xc000;
-       u_long mem_addr = base_addr + 0x8000; /* 32KB */
-
-       /* Can't reserve the prom region, it is already marked as
-        * used, at least on x86. Instead, reserve a memory region a
-        * board would certainly use. If it works, go ahead. If not,
-        * run like hell... */
-
-       if (!request_mem_region (mem_addr, 16, depca_string))
-               return unknown;
-
-       /* Copy the first 16 bytes of ROM */
-
-       ptr = ioremap(prom_addr, 16);
-       if (ptr == NULL) {
-               printk(KERN_ERR "depca: I/O remap failed at %lx\n", prom_addr);
-               return unknown;
-       }
-       for (i = 0; i < 16; i++) {
-               tmpstr[i] = readb(ptr + i);
-       }
-       iounmap(ptr);
-
-       release_mem_region (mem_addr, 16);
-
-       /* Check if PROM contains a valid string */
-       for (i = 0; *depca_signature[i] != '\0'; i++) {
-               for (j = 0, k = 0; j < 16 && k < strlen(depca_signature[i]); j++) {
-                       if (depca_signature[i][k] == tmpstr[j]) {       /* track signature */
-                               k++;
-                       } else {        /* lost signature; begin search again */
-                               k = 0;
-                       }
-               }
-               if (k == strlen(depca_signature[i]))
-                       break;
-       }
-
-       /* Check if name string is valid, provided there's no PROM */
-       if (name && *name && (i == unknown)) {
-               for (i = 0; *depca_signature[i] != '\0'; i++) {
-                       if (strcmp(name, depca_signature[i]) == 0)
-                               break;
-               }
-       }
-
-       return i;
-}
-
-/*
-** Look for a special sequence in the Ethernet station address PROM that
-** is common across all DEPCA products. Note that the original DEPCA needs
-** its ROM address counter to be initialized and enabled. Only enable
-** if the first address octet is a 0x08 - this minimises the chances of
-** messing around with some other hardware, but it assumes that this DEPCA
-** card initialized itself correctly.
-**
-** Search the Ethernet address ROM for the signature. Since the ROM address
-** counter can start at an arbitrary point, the search must include the entire
-** probe sequence length plus the (length_of_the_signature - 1).
-** Stop the search IMMEDIATELY after the signature is found so that the
-** PROM address counter is correctly positioned at the start of the
-** ethernet address for later read out.
-*/
-static int __init DevicePresent(u_long ioaddr)
-{
-       union {
-               struct {
-                       u32 a;
-                       u32 b;
-               } llsig;
-               char Sig[sizeof(u32) << 1];
-       }
-       dev;
-       short sigLength = 0;
-       s8 data;
-       s16 nicsr;
-       int i, j, status = 0;
-
-       data = inb(DEPCA_PROM); /* clear counter on DEPCA */
-       data = inb(DEPCA_PROM); /* read data */
-
-       if (data == 0x08) {     /* Enable counter on DEPCA */
-               nicsr = inb(DEPCA_NICSR);
-               nicsr |= AAC;
-               outb(nicsr, DEPCA_NICSR);
-       }
-
-       dev.llsig.a = ETH_PROM_SIG;
-       dev.llsig.b = ETH_PROM_SIG;
-       sigLength = sizeof(u32) << 1;
-
-       for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
-               data = inb(DEPCA_PROM);
-               if (dev.Sig[j] == data) {       /* track signature */
-                       j++;
-               } else {        /* lost signature; begin search again */
-                       if (data == dev.Sig[0]) {       /* rare case.... */
-                               j = 1;
-                       } else {
-                               j = 0;
-                       }
-               }
-       }
-
-       if (j != sigLength) {
-               status = -ENODEV;       /* search failed */
-       }
-
-       return status;
-}
-
-/*
-** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
-** reason: access the upper half of the PROM with x=0; access the lower half
-** with x=1.
-*/
-static int __init get_hw_addr(struct net_device *dev)
-{
-       u_long ioaddr = dev->base_addr;
-       struct depca_private *lp = netdev_priv(dev);
-       int i, k, tmp, status = 0;
-       u_short j, x, chksum;
-
-       x = (((lp->adapter == de100) || (lp->adapter == de101)) ? 1 : 0);
-
-       for (i = 0, k = 0, j = 0; j < 3; j++) {
-               k <<= 1;
-               if (k > 0xffff)
-                       k -= 0xffff;
-
-               k += (u_char) (tmp = inb(DEPCA_PROM + x));
-               dev->dev_addr[i++] = (u_char) tmp;
-               k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
-               dev->dev_addr[i++] = (u_char) tmp;
-
-               if (k > 0xffff)
-                       k -= 0xffff;
-       }
-       if (k == 0xffff)
-               k = 0;
-
-       chksum = (u_char) inb(DEPCA_PROM + x);
-       chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
-       if (k != chksum)
-               status = -1;
-
-       return status;
-}
-
-/*
-** Load a packet into the shared memory
-*/
-static int load_packet(struct net_device *dev, struct sk_buff *skb)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       int i, entry, end, len, status = NETDEV_TX_OK;
-
-       entry = lp->tx_new;     /* Ring around buffer number. */
-       end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
-       if (!(readl(&lp->tx_ring[end].base) & T_OWN)) { /* Enough room? */
-               /*
-                  ** Caution: the write order is important here... don't set up the
-                  ** ownership rights until all the other information is in place.
-                */
-               if (end < entry) {      /* wrapped buffer */
-                       len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
-                       memcpy_toio(lp->tx_buff[entry], skb->data, len);
-                       memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
-               } else {        /* linear buffer */
-                       memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
-               }
-
-               /* set up the buffer descriptors */
-               len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-               for (i = entry; i != end; i = (i+1) & lp->txRingMask) {
-                       /* clean out flags */
-                       writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
-                       writew(0x0000, &lp->tx_ring[i].misc);   /* clears other error flags */
-                       writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);    /* packet length in buffer */
-                       len -= TX_BUFF_SZ;
-               }
-               /* clean out flags */
-               writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
-               writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */
-               writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */
-
-               /* start of packet */
-               writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
-               /* end of packet */
-               writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
-
-               for (i = end; i != entry; --i) {
-                       /* ownership of packet */
-                       writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
-                       if (i == 0)
-                               i = lp->txRingMask + 1;
-               }
-               writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
-
-               lp->tx_new = (++end) & lp->txRingMask;  /* update current pointers */
-       } else {
-               status = NETDEV_TX_LOCKED;
-       }
-
-       return status;
-}
-
-static void depca_dbg_open(struct net_device *dev)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       u_long ioaddr = dev->base_addr;
-       struct depca_init *p = &lp->init_block;
-       int i;
-
-       if (depca_debug > 1) {
-               /* Do not copy the shadow init block into shared memory */
-               /* Debugging should not affect normal operation! */
-               /* The shadow init block will get copied across during InitRestartDepca */
-               printk("%s: depca open with irq %d\n", dev->name, dev->irq);
-               printk("Descriptor head addresses (CPU):\n");
-               printk("        0x%lx  0x%lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring);
-               printk("Descriptor addresses (CPU):\nRX: ");
-               for (i = 0; i < lp->rxRingMask; i++) {
-                       if (i < 3) {
-                               printk("%p ", &lp->rx_ring[i].base);
-                       }
-               }
-               printk("...%p\n", &lp->rx_ring[i].base);
-               printk("TX: ");
-               for (i = 0; i < lp->txRingMask; i++) {
-                       if (i < 3) {
-                               printk("%p ", &lp->tx_ring[i].base);
-                       }
-               }
-               printk("...%p\n", &lp->tx_ring[i].base);
-               printk("\nDescriptor buffers (Device):\nRX: ");
-               for (i = 0; i < lp->rxRingMask; i++) {
-                       if (i < 3) {
-                               printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
-                       }
-               }
-               printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
-               printk("TX: ");
-               for (i = 0; i < lp->txRingMask; i++) {
-                       if (i < 3) {
-                               printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
-                       }
-               }
-               printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
-               printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
-               printk("        mode: 0x%4.4x\n", p->mode);
-               printk("        physical address: %pM\n", p->phys_addr);
-               printk("        multicast hash table: ");
-               for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
-                       printk("%2.2x:", p->mcast_table[i]);
-               }
-               printk("%2.2x\n", p->mcast_table[i]);
-               printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
-               printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
-               printk("buffers (Phys): 0x%8.8lx\n", lp->mem_start + lp->buffs_offset);
-               printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen);
-               printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
-               outw(CSR2, DEPCA_ADDR);
-               printk("CSR2&1: 0x%4.4x", inw(DEPCA_DATA));
-               outw(CSR1, DEPCA_ADDR);
-               printk("%4.4x\n", inw(DEPCA_DATA));
-               outw(CSR3, DEPCA_ADDR);
-               printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA));
-       }
-}
-
-/*
-** Perform IOCTL call functions here. Some are privileged operations and the
-** effective uid is checked in those cases.
-** All multicast IOCTLs will not work here and are for testing purposes only.
-*/
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct depca_private *lp = netdev_priv(dev);
-       struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru;
-       int i, status = 0;
-       u_long ioaddr = dev->base_addr;
-       union {
-               u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
-               u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-               u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
-       } tmp;
-       unsigned long flags;
-       void *buf;
-
-       switch (ioc->cmd) {
-       case DEPCA_GET_HWADDR:  /* Get the hardware address */
-               for (i = 0; i < ETH_ALEN; i++) {
-                       tmp.addr[i] = dev->dev_addr[i];
-               }
-               ioc->len = ETH_ALEN;
-               if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-                       return -EFAULT;
-               break;
-
-       case DEPCA_SET_HWADDR:  /* Set the hardware address */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
-                       return -EFAULT;
-               for (i = 0; i < ETH_ALEN; i++) {
-                       dev->dev_addr[i] = tmp.addr[i];
-               }
-               netif_stop_queue(dev);
-               while (lp->tx_old != lp->tx_new)
-                       cpu_relax();    /* Wait for the ring to empty */
-
-               STOP_DEPCA;     /* Temporarily stop the depca.  */
-               depca_init_ring(dev);   /* Initialize the descriptor rings */
-               LoadCSRs(dev);  /* Reload CSR3 */
-               InitRestartDepca(dev);  /* Resume normal operation. */
-               netif_start_queue(dev); /* Unlock the TX ring */
-               break;
-
-       case DEPCA_SET_PROM:    /* Set Promiscuous Mode */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               netif_stop_queue(dev);
-               while (lp->tx_old != lp->tx_new)
-                       cpu_relax();    /* Wait for the ring to empty */
-
-               STOP_DEPCA;     /* Temporarily stop the depca.  */
-               depca_init_ring(dev);   /* Initialize the descriptor rings */
-               lp->init_block.mode |= PROM;    /* Set promiscuous mode */
-
-               LoadCSRs(dev);  /* Reload CSR3 */
-               InitRestartDepca(dev);  /* Resume normal operation. */
-               netif_start_queue(dev); /* Unlock the TX ring */
-               break;
-
-       case DEPCA_CLR_PROM:    /* Clear Promiscuous Mode */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               netif_stop_queue(dev);
-               while (lp->tx_old != lp->tx_new)
-                       cpu_relax();    /* Wait for the ring to empty */
-
-               STOP_DEPCA;     /* Temporarily stop the depca.  */
-               depca_init_ring(dev);   /* Initialize the descriptor rings */
-               lp->init_block.mode &= ~PROM;   /* Clear promiscuous mode */
-
-               LoadCSRs(dev);  /* Reload CSR3 */
-               InitRestartDepca(dev);  /* Resume normal operation. */
-               netif_start_queue(dev); /* Unlock the TX ring */
-               break;
-
-       case DEPCA_SAY_BOO:     /* Say "Boo!" to the kernel log file */
-               if(!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               printk("%s: Boo!\n", dev->name);
-               break;
-
-       case DEPCA_GET_MCA:     /* Get the multicast address table */
-               ioc->len = (HASH_TABLE_LEN >> 3);
-               if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
-                       return -EFAULT;
-               break;
-
-       case DEPCA_SET_MCA:     /* Set a multicast address */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               if (ioc->len >= HASH_TABLE_LEN)
-                       return -EINVAL;
-               if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
-                       return -EFAULT;
-               set_multicast_list(dev);
-               break;
-
-       case DEPCA_CLR_MCA:     /* Clear all multicast addresses */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               set_multicast_list(dev);
-               break;
-
-       case DEPCA_MCA_EN:      /* Enable pass all multicast addressing */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               set_multicast_list(dev);
-               break;
-
-       case DEPCA_GET_STATS:   /* Get the driver statistics */
-               ioc->len = sizeof(lp->pktStats);
-               buf = kmalloc(ioc->len, GFP_KERNEL);
-               if(!buf)
-                       return -ENOMEM;
-               spin_lock_irqsave(&lp->lock, flags);
-               memcpy(buf, &lp->pktStats, ioc->len);
-               spin_unlock_irqrestore(&lp->lock, flags);
-               if (copy_to_user(ioc->data, buf, ioc->len))
-                       status = -EFAULT;
-               kfree(buf);
-               break;
-
-       case DEPCA_CLR_STATS:   /* Zero out the driver statistics */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               spin_lock_irqsave(&lp->lock, flags);
-               memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-               spin_unlock_irqrestore(&lp->lock, flags);
-               break;
-
-       case DEPCA_GET_REG:     /* Get the DEPCA Registers */
-               i = 0;
-               tmp.sval[i++] = inw(DEPCA_NICSR);
-               outw(CSR0, DEPCA_ADDR); /* status register */
-               tmp.sval[i++] = inw(DEPCA_DATA);
-               memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
-               ioc->len = i + sizeof(struct depca_init);
-               if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-                       return -EFAULT;
-               break;
-
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       return status;
-}
-
-static int __init depca_module_init (void)
-{
-       int err = 0;
-
-#ifdef CONFIG_EISA
-       err = eisa_driver_register(&depca_eisa_driver);
-       if (err)
-               goto err_eisa;
-#endif
-       err = platform_driver_register(&depca_isa_driver);
-       if (err)
-               goto err_eisa;
-
-       depca_platform_probe();
-       return 0;
-
-err_eisa:
-#ifdef CONFIG_EISA
-       eisa_driver_unregister(&depca_eisa_driver);
-#endif
-       return err;
-}
-
-static void __exit depca_module_exit (void)
-{
-       int i;
-#ifdef CONFIG_EISA
-        eisa_driver_unregister (&depca_eisa_driver);
-#endif
-       platform_driver_unregister (&depca_isa_driver);
-
-       for (i = 0; depca_io_ports[i].iobase; i++) {
-               if (depca_io_ports[i].device) {
-                       depca_io_ports[i].device->dev.platform_data = NULL;
-                       platform_device_unregister (depca_io_ports[i].device);
-                       depca_io_ports[i].device = NULL;
-               }
-       }
-}
-
-module_init (depca_module_init);
-module_exit (depca_module_exit);
diff --git a/drivers/net/ethernet/amd/depca.h b/drivers/net/ethernet/amd/depca.h
deleted file mode 100644 (file)
index cdcfe42..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
-    Written 1994 by David C. Davies.
-
-    Copyright 1994 David C. Davies. This software may be used and distributed
-    according to the terms of the GNU General Public License, incorporated herein by
-    reference.
-*/
-
-/*
-** I/O addresses. Note that the 2k buffer option is not supported in
-** this driver.
-*/
-#define DEPCA_NICSR ioaddr+0x00   /* Network interface CSR */
-#define DEPCA_RBI   ioaddr+0x02   /* RAM buffer index (2k buffer mode) */
-#define DEPCA_DATA  ioaddr+0x04   /* LANCE registers' data port */
-#define DEPCA_ADDR  ioaddr+0x06   /* LANCE registers' address port */
-#define DEPCA_HBASE ioaddr+0x08   /* EISA high memory base address reg. */
-#define DEPCA_PROM  ioaddr+0x0c   /* Ethernet address ROM data port */
-#define DEPCA_CNFG  ioaddr+0x0c   /* EISA Configuration port */
-#define DEPCA_RBSA  ioaddr+0x0e   /* RAM buffer starting address (2k buff.) */
-
-/*
-** These are LANCE registers addressable through DEPCA_ADDR
-*/
-#define CSR0       0
-#define CSR1       1
-#define CSR2       2
-#define CSR3       3
-
-/*
-** NETWORK INTERFACE CSR (NI_CSR) bit definitions
-*/
-
-#define TO             0x0100  /* Time Out for remote boot */
-#define SHE            0x0080  /* SHadow memory Enable */
-#define BS             0x0040  /* Bank Select */
-#define BUF            0x0020  /* BUFfer size (1->32k, 0->64k) */
-#define RBE            0x0010  /* Remote Boot Enable (1->net boot) */
-#define AAC            0x0008  /* Address ROM Address Counter (1->enable) */
-#define _128KB         0x0008  /* 128kB Network RAM (1->enable) */
-#define IM             0x0004  /* Interrupt Mask (1->mask) */
-#define IEN            0x0002  /* Interrupt tristate ENable (1->enable) */
-#define LED            0x0001  /* LED control */
-
-/*
-** Control and Status Register 0 (CSR0) bit definitions
-*/
-
-#define ERR            0x8000  /* Error summary */
-#define BABL           0x4000  /* Babble transmitter timeout error  */
-#define CERR           0x2000  /* Collision Error */
-#define MISS           0x1000  /* Missed packet */
-#define MERR           0x0800  /* Memory Error */
-#define RINT           0x0400  /* Receiver Interrupt */
-#define TINT           0x0200  /* Transmit Interrupt */
-#define IDON           0x0100  /* Initialization Done */
-#define INTR           0x0080  /* Interrupt Flag */
-#define INEA           0x0040  /* Interrupt Enable */
-#define RXON           0x0020  /* Receiver on */
-#define TXON           0x0010  /* Transmitter on */
-#define TDMD           0x0008  /* Transmit Demand */
-#define STOP           0x0004  /* Stop */
-#define STRT           0x0002  /* Start */
-#define INIT           0x0001  /* Initialize */
-#define INTM            0xff00  /* Interrupt Mask */
-#define INTE            0xfff0  /* Interrupt Enable */
-
-/*
-** CONTROL AND STATUS REGISTER 3 (CSR3)
-*/
-
-#define BSWP           0x0004  /* Byte SWaP */
-#define ACON           0x0002  /* ALE control */
-#define BCON           0x0001  /* Byte CONtrol */
-
-/*
-** Initialization Block Mode Register
-*/
-
-#define PROM           0x8000  /* Promiscuous Mode */
-#define EMBA           0x0080  /* Enable Modified Back-off Algorithm */
-#define INTL           0x0040  /* Internal Loopback */
-#define DRTY           0x0020  /* Disable Retry */
-#define COLL           0x0010  /* Force Collision */
-#define DTCR           0x0008  /* Disable Transmit CRC */
-#define LOOP           0x0004  /* Loopback */
-#define DTX            0x0002  /* Disable the Transmitter */
-#define DRX            0x0001  /* Disable the Receiver */
-
-/*
-** Receive Message Descriptor 1 (RMD1) bit definitions.
-*/
-
-#define R_OWN       0x80000000         /* Owner bit 0 = host, 1 = lance */
-#define R_ERR          0x4000  /* Error Summary */
-#define R_FRAM         0x2000  /* Framing Error */
-#define R_OFLO         0x1000  /* Overflow Error */
-#define R_CRC          0x0800  /* CRC Error */
-#define R_BUFF         0x0400  /* Buffer Error */
-#define R_STP          0x0200  /* Start of Packet */
-#define R_ENP          0x0100  /* End of Packet */
-
-/*
-** Transmit Message Descriptor 1 (TMD1) bit definitions.
-*/
-
-#define T_OWN       0x80000000         /* Owner bit 0 = host, 1 = lance */
-#define T_ERR          0x4000  /* Error Summary */
-#define T_ADD_FCS      0x2000  /* More the 1 retry needed to Xmit */
-#define T_MORE         0x1000  /* >1 retry to transmit packet */
-#define T_ONE          0x0800  /* 1 try needed to transmit the packet */
-#define T_DEF          0x0400  /* Deferred */
-#define T_STP       0x02000000         /* Start of Packet */
-#define T_ENP       0x01000000 /* End of Packet */
-#define T_FLAGS     0xff000000  /* TX Flags Field */
-
-/*
-** Transmit Message Descriptor 3 (TMD3) bit definitions.
-*/
-
-#define TMD3_BUFF    0x8000    /* BUFFer error */
-#define TMD3_UFLO    0x4000    /* UnderFLOw error */
-#define TMD3_RES     0x2000    /* REServed */
-#define TMD3_LCOL    0x1000    /* Late COLlision */
-#define TMD3_LCAR    0x0800    /* Loss of CARrier */
-#define TMD3_RTRY    0x0400    /* ReTRY error */
-
-/*
-** EISA configuration Register (CNFG) bit definitions
-*/
-
-#define TIMEOUT        0x0100  /* 0:2.5 mins, 1: 30 secs */
-#define REMOTE         0x0080  /* Remote Boot Enable -> 1 */
-#define IRQ11          0x0040  /* Enable -> 1 */
-#define IRQ10          0x0020  /* Enable -> 1 */
-#define IRQ9           0x0010  /* Enable -> 1 */
-#define IRQ5           0x0008  /* Enable -> 1 */
-#define BUFF           0x0004  /* 0: 64kB or 128kB, 1: 32kB */
-#define PADR16         0x0002  /* RAM on 64kB boundary */
-#define PADR17         0x0001  /* RAM on 128kB boundary */
-
-/*
-** Miscellaneous
-*/
-#define HASH_TABLE_LEN   64           /* Bits */
-#define HASH_BITS        0x003f       /* 6 LS bits */
-
-#define MASK_INTERRUPTS   1
-#define UNMASK_INTERRUPTS 0
-
-#define EISA_EN         0x0001        /* Enable EISA bus buffers */
-#define EISA_ID         iobase+0x0080 /* ID long word for EISA card */
-#define EISA_CTRL       iobase+0x0084 /* Control word for EISA card */
-
-/*
-** Include the IOCTL stuff
-*/
-#include <linux/sockios.h>
-
-struct depca_ioctl {
-       unsigned short cmd;                /* Command to run */
-       unsigned short len;                /* Length of the data buffer */
-       unsigned char  __user *data;       /* Pointer to the data buffer */
-};
-
-/*
-** Recognised commands for the driver
-*/
-#define DEPCA_GET_HWADDR       0x01 /* Get the hardware address */
-#define DEPCA_SET_HWADDR       0x02 /* Get the hardware address */
-#define DEPCA_SET_PROM         0x03 /* Set Promiscuous Mode */
-#define DEPCA_CLR_PROM         0x04 /* Clear Promiscuous Mode */
-#define DEPCA_SAY_BOO          0x05 /* Say "Boo!" to the kernel log file */
-#define DEPCA_GET_MCA          0x06 /* Get a multicast address */
-#define DEPCA_SET_MCA          0x07 /* Set a multicast address */
-#define DEPCA_CLR_MCA          0x08 /* Clear a multicast address */
-#define DEPCA_MCA_EN           0x09 /* Enable a multicast address group */
-#define DEPCA_GET_STATS        0x0a /* Get the driver statistics */
-#define DEPCA_CLR_STATS        0x0b /* Zero out the driver statistics */
-#define DEPCA_GET_REG          0x0c /* Get the Register contents */
-#define DEPCA_SET_REG          0x0d /* Set the Register contents */
-#define DEPCA_DUMP              0x0f /* Dump the DEPCA Status */
-
index a227ccdcb9b5e94447a5cd3c23c9ebef94b08932..74cfc017adcf036160d2a868046b1ddf117c360b 100644 (file)
@@ -1688,10 +1688,9 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
                        memcpy(dev->dev_addr, promaddr, 6);
                }
        }
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
-       if (!is_valid_ether_addr(dev->perm_addr))
+       if (!is_valid_ether_addr(dev->dev_addr))
                memset(dev->dev_addr, 0, ETH_ALEN);
 
        if (pcnet32_debug & NETIF_MSG_PROBE) {
index c2d696c88e4687c46233b017429f2fc86c9aca8f..6a40290d3727579f2a3fd0b1009e5ef3d2323e06 100644 (file)
@@ -1284,8 +1284,8 @@ static void lance_free_hwresources(struct lance_private *lp)
 /* Ethtool support... */
 static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "sunlance");
-       strcpy(info->version, "2.02");
+       strlcpy(info->driver, "sunlance", sizeof(info->driver));
+       strlcpy(info->version, "2.02", sizeof(info->version));
 }
 
 static const struct ethtool_ops sparc_lance_ethtool_ops = {
index 56d3f697e0c7f0a05d8044a37f954c8d536f1c0a..8df02ba2ce46fbda01d0c43539b26b8565a33db3 100644 (file)
@@ -472,7 +472,6 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
 
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
-       netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
        atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr);
 
@@ -2540,10 +2539,9 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        if (atl1c_read_mac_addr(&adapter->hw)) {
                /* got a random MAC address, set NET_ADDR_RANDOM to netdev */
-               netdev->addr_assign_type |= NET_ADDR_RANDOM;
+               netdev->addr_assign_type = NET_ADDR_RANDOM;
        }
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
-       memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
        if (netif_msg_probe(adapter))
                dev_dbg(&pdev->dev, "mac address : %pM\n",
                        adapter->hw.mac_addr);
index e4466a36d1063b38c71b3937ba5cc055482ab82a..cf79d932fa3570512a208514ce9638bd947f7500 100644 (file)
@@ -2342,7 +2342,6 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
-       memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
        netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr);
 
        INIT_WORK(&adapter->reset_task, atl1e_reset_task);
index 71b3d7daa21d06c70e4b62732c91b04137342c64..5b0d9931c720f9beb3f21b721527d01c98781960 100644 (file)
@@ -3053,7 +3053,7 @@ static int atl1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* copy the MAC address out of the EEPROM */
        if (atl1_read_mac_addr(&adapter->hw)) {
                /* mark random mac */
-               netdev->addr_assign_type |= NET_ADDR_RANDOM;
+               netdev->addr_assign_type = NET_ADDR_RANDOM;
        }
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
 
index aab83a2d4e0770a2cb781c5e6062bdb42360e413..1278b47022e0d2cf2b406e7adbefa7168c25274b 100644 (file)
@@ -1433,14 +1433,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* copy the MAC address out of the EEPROM */
        atl2_read_mac_addr(&adapter->hw);
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
-/* FIXME: do we still need this? */
-#ifdef ETHTOOL_GPERMADDR
-       memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
-
-       if (!is_valid_ether_addr(netdev->perm_addr)) {
-#else
        if (!is_valid_ether_addr(netdev->dev_addr)) {
-#endif
                err = -EIO;
                goto err_eeprom;
        }
index 77ffbc4a5071f491222ef231b3c3d82e3a37bdfe..f82eb16994640388e8fa96b90333c79d1abcc6f8 100644 (file)
@@ -84,7 +84,6 @@ static int atlx_set_mac(struct net_device *netdev, void *p)
 
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
-       netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
        atlx_set_mac_addr(&adapter->hw);
        return 0;
index f55267363f355d1238dfecf9eb8df1367f53aad1..3e69b3f88099ba931c9f6b18f4a71da82d182bdc 100644 (file)
@@ -121,4 +121,22 @@ config BNX2X
          To compile this driver as a module, choose M here: the module
          will be called bnx2x.  This is recommended.
 
+config BNX2X_SRIOV
+       bool "Broadcom 578xx and 57712 SR-IOV support"
+       depends on BNX2X && PCI_IOV
+       default y
+       ---help---
+         This configuration parameter enables Single Root Input Output
+         Virtualization support in the 578xx and 57712 products. This
+         allows for virtual function acceleration in virtual environments.
+
+config BGMAC
+       tristate "BCMA bus GBit core support"
+       depends on BCMA_HOST_SOC && HAS_DMA
+       ---help---
+         This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
+         They can be found on BCM47xx SoCs and provide gigabit ethernet.
+         In case of using this driver on BCM4706 it's also requires to enable
+         BCMA_DRIVER_GMAC_CMN to make it work.
+
 endif # NET_VENDOR_BROADCOM
index b7896051d54e215e2d8966c3c178853663cc691d..68efa1a3fb8820ed71ca1e565cf08c9f243bc55e 100644 (file)
@@ -9,3 +9,4 @@ obj-$(CONFIG_CNIC) += cnic.o
 obj-$(CONFIG_BNX2X) += bnx2x/
 obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_BGMAC) += bgmac.o
index 219f6226fcb139a50795da6af0f4daa5a8ceb12a..3ba6be689e7dff8a40ce3368d2b4b0fa39de7772 100644 (file)
@@ -2111,8 +2111,6 @@ static int b44_get_invariants(struct b44 *bp)
                return -EINVAL;
        }
 
-       memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
-
        bp->imask = IMASK_DEF;
 
        /* XXX - really required?
index 39387d67b7222beee3a5fd122218c645851f90c6..f5b6b4715d455c167717ae94521f4bdc6b7bf369 100644 (file)
@@ -799,7 +799,7 @@ static int bcm_enet_open(struct net_device *dev)
                snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
                         priv->mii_bus->id, priv->phy_id);
 
-               phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, 0,
+               phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link,
                                     PHY_INTERFACE_MODE_MII);
 
                if (IS_ERR(phydev)) {
@@ -1227,10 +1227,11 @@ static const u32 unused_mib_regs[] = {
 static void bcm_enet_get_drvinfo(struct net_device *netdev,
                                 struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver, bcm_enet_driver_name, 32);
-       strncpy(drvinfo->version, bcm_enet_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, "bcm63xx", 32);
+       strlcpy(drvinfo->driver, bcm_enet_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, bcm_enet_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, "bcm63xx", sizeof(drvinfo->bus_info));
        drvinfo->n_stats = BCM_ENET_STATS_LEN;
 }
 
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
new file mode 100644 (file)
index 0000000..9bd33db
--- /dev/null
@@ -0,0 +1,1422 @@
+/*
+ * Driver for (BCM4706)? GBit MAC core on BCMA bus.
+ *
+ * Copyright (C) 2012 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bgmac.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <asm/mach-bcm47xx/nvram.h>
+
+static const struct bcma_device_id bgmac_bcma_tbl[] = {
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+       BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
+
+static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask,
+                            u32 value, int timeout)
+{
+       u32 val;
+       int i;
+
+       for (i = 0; i < timeout / 10; i++) {
+               val = bcma_read32(core, reg);
+               if ((val & mask) == value)
+                       return true;
+               udelay(10);
+       }
+       pr_err("Timeout waiting for reg 0x%X\n", reg);
+       return false;
+}
+
+/**************************************************
+ * DMA
+ **************************************************/
+
+static void bgmac_dma_tx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+       u32 val;
+       int i;
+
+       if (!ring->mmio_base)
+               return;
+
+       /* Suspend DMA TX ring first.
+        * bgmac_wait_value doesn't support waiting for any of few values, so
+        * implement whole loop here.
+        */
+       bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL,
+                   BGMAC_DMA_TX_SUSPEND);
+       for (i = 0; i < 10000 / 10; i++) {
+               val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+               val &= BGMAC_DMA_TX_STAT;
+               if (val == BGMAC_DMA_TX_STAT_DISABLED ||
+                   val == BGMAC_DMA_TX_STAT_IDLEWAIT ||
+                   val == BGMAC_DMA_TX_STAT_STOPPED) {
+                       i = 0;
+                       break;
+               }
+               udelay(10);
+       }
+       if (i)
+               bgmac_err(bgmac, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
+                         ring->mmio_base, val);
+
+       /* Remove SUSPEND bit */
+       bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, 0);
+       if (!bgmac_wait_value(bgmac->core,
+                             ring->mmio_base + BGMAC_DMA_TX_STATUS,
+                             BGMAC_DMA_TX_STAT, BGMAC_DMA_TX_STAT_DISABLED,
+                             10000)) {
+               bgmac_warn(bgmac, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
+                          ring->mmio_base);
+               udelay(300);
+               val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+               if ((val & BGMAC_DMA_TX_STAT) != BGMAC_DMA_TX_STAT_DISABLED)
+                       bgmac_err(bgmac, "Reset of DMA TX ring 0x%X failed\n",
+                                 ring->mmio_base);
+       }
+}
+
+static void bgmac_dma_tx_enable(struct bgmac *bgmac,
+                               struct bgmac_dma_ring *ring)
+{
+       u32 ctl;
+
+       ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL);
+       ctl |= BGMAC_DMA_TX_ENABLE;
+       ctl |= BGMAC_DMA_TX_PARITY_DISABLE;
+       bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl);
+}
+
+static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
+                                   struct bgmac_dma_ring *ring,
+                                   struct sk_buff *skb)
+{
+       struct device *dma_dev = bgmac->core->dma_dev;
+       struct net_device *net_dev = bgmac->net_dev;
+       struct bgmac_dma_desc *dma_desc;
+       struct bgmac_slot_info *slot;
+       u32 ctl0, ctl1;
+       int free_slots;
+
+       if (skb->len > BGMAC_DESC_CTL1_LEN) {
+               bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
+               goto err_stop_drop;
+       }
+
+       if (ring->start <= ring->end)
+               free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
+       else
+               free_slots = ring->start - ring->end;
+       if (free_slots == 1) {
+               bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
+               netif_stop_queue(net_dev);
+               return NETDEV_TX_BUSY;
+       }
+
+       slot = &ring->slots[ring->end];
+       slot->skb = skb;
+       slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len,
+                                       DMA_TO_DEVICE);
+       if (dma_mapping_error(dma_dev, slot->dma_addr)) {
+               bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
+                         ring->mmio_base);
+               goto err_stop_drop;
+       }
+
+       ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF;
+       if (ring->end == ring->num_slots - 1)
+               ctl0 |= BGMAC_DESC_CTL0_EOT;
+       ctl1 = skb->len & BGMAC_DESC_CTL1_LEN;
+
+       dma_desc = ring->cpu_base;
+       dma_desc += ring->end;
+       dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
+       dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
+       dma_desc->ctl0 = cpu_to_le32(ctl0);
+       dma_desc->ctl1 = cpu_to_le32(ctl1);
+
+       wmb();
+
+       /* Increase ring->end to point empty slot. We tell hardware the first
+        * slot it should *not* read.
+        */
+       if (++ring->end >= BGMAC_TX_RING_SLOTS)
+               ring->end = 0;
+       bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
+                   ring->end * sizeof(struct bgmac_dma_desc));
+
+       /* Always keep one slot free to allow detecting bugged calls. */
+       if (--free_slots == 1)
+               netif_stop_queue(net_dev);
+
+       return NETDEV_TX_OK;
+
+err_stop_drop:
+       netif_stop_queue(net_dev);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+/* Free transmitted packets */
+static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+       struct device *dma_dev = bgmac->core->dma_dev;
+       int empty_slot;
+       bool freed = false;
+
+       /* The last slot that hardware didn't consume yet */
+       empty_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+       empty_slot &= BGMAC_DMA_TX_STATDPTR;
+       empty_slot /= sizeof(struct bgmac_dma_desc);
+
+       while (ring->start != empty_slot) {
+               struct bgmac_slot_info *slot = &ring->slots[ring->start];
+
+               if (slot->skb) {
+                       /* Unmap no longer used buffer */
+                       dma_unmap_single(dma_dev, slot->dma_addr,
+                                        slot->skb->len, DMA_TO_DEVICE);
+                       slot->dma_addr = 0;
+
+                       /* Free memory! :) */
+                       dev_kfree_skb(slot->skb);
+                       slot->skb = NULL;
+               } else {
+                       bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
+                                 ring->start, ring->end);
+               }
+
+               if (++ring->start >= BGMAC_TX_RING_SLOTS)
+                       ring->start = 0;
+               freed = true;
+       }
+
+       if (freed && netif_queue_stopped(bgmac->net_dev))
+               netif_wake_queue(bgmac->net_dev);
+}
+
+static void bgmac_dma_rx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+       if (!ring->mmio_base)
+               return;
+
+       bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, 0);
+       if (!bgmac_wait_value(bgmac->core,
+                             ring->mmio_base + BGMAC_DMA_RX_STATUS,
+                             BGMAC_DMA_RX_STAT, BGMAC_DMA_RX_STAT_DISABLED,
+                             10000))
+               bgmac_err(bgmac, "Reset of ring 0x%X RX failed\n",
+                         ring->mmio_base);
+}
+
+static void bgmac_dma_rx_enable(struct bgmac *bgmac,
+                               struct bgmac_dma_ring *ring)
+{
+       u32 ctl;
+
+       ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL);
+       ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
+       ctl |= BGMAC_DMA_RX_ENABLE;
+       ctl |= BGMAC_DMA_RX_PARITY_DISABLE;
+       ctl |= BGMAC_DMA_RX_OVERFLOW_CONT;
+       ctl |= BGMAC_RX_FRAME_OFFSET << BGMAC_DMA_RX_FRAME_OFFSET_SHIFT;
+       bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, ctl);
+}
+
+static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
+                                    struct bgmac_slot_info *slot)
+{
+       struct device *dma_dev = bgmac->core->dma_dev;
+       struct bgmac_rx_header *rx;
+
+       /* Alloc skb */
+       slot->skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
+       if (!slot->skb) {
+               bgmac_err(bgmac, "Allocation of skb failed!\n");
+               return -ENOMEM;
+       }
+
+       /* Poison - if everything goes fine, hardware will overwrite it */
+       rx = (struct bgmac_rx_header *)slot->skb->data;
+       rx->len = cpu_to_le16(0xdead);
+       rx->flags = cpu_to_le16(0xbeef);
+
+       /* Map skb for the DMA */
+       slot->dma_addr = dma_map_single(dma_dev, slot->skb->data,
+                                       BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+       if (dma_mapping_error(dma_dev, slot->dma_addr)) {
+               bgmac_err(bgmac, "DMA mapping error\n");
+               return -ENOMEM;
+       }
+       if (slot->dma_addr & 0xC0000000)
+               bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+       return 0;
+}
+
+static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
+                            int weight)
+{
+       u32 end_slot;
+       int handled = 0;
+
+       end_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS);
+       end_slot &= BGMAC_DMA_RX_STATDPTR;
+       end_slot /= sizeof(struct bgmac_dma_desc);
+
+       ring->end = end_slot;
+
+       while (ring->start != ring->end) {
+               struct device *dma_dev = bgmac->core->dma_dev;
+               struct bgmac_slot_info *slot = &ring->slots[ring->start];
+               struct sk_buff *skb = slot->skb;
+               struct sk_buff *new_skb;
+               struct bgmac_rx_header *rx;
+               u16 len, flags;
+
+               /* Unmap buffer to make it accessible to the CPU */
+               dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
+                                       BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+               /* Get info from the header */
+               rx = (struct bgmac_rx_header *)skb->data;
+               len = le16_to_cpu(rx->len);
+               flags = le16_to_cpu(rx->flags);
+
+               /* Check for poison and drop or pass the packet */
+               if (len == 0xdead && flags == 0xbeef) {
+                       bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
+                                 ring->start);
+               } else {
+                       new_skb = netdev_alloc_skb(bgmac->net_dev, len);
+                       if (new_skb) {
+                               skb_put(new_skb, len);
+                               skb_copy_from_linear_data_offset(skb, BGMAC_RX_FRAME_OFFSET,
+                                                                new_skb->data,
+                                                                len);
+                               new_skb->protocol =
+                                       eth_type_trans(new_skb, bgmac->net_dev);
+                               netif_receive_skb(new_skb);
+                               handled++;
+                       } else {
+                               bgmac->net_dev->stats.rx_dropped++;
+                               bgmac_err(bgmac, "Allocation of skb for copying packet failed!\n");
+                       }
+
+                       /* Poison the old skb */
+                       rx->len = cpu_to_le16(0xdead);
+                       rx->flags = cpu_to_le16(0xbeef);
+               }
+
+               /* Make it back accessible to the hardware */
+               dma_sync_single_for_device(dma_dev, slot->dma_addr,
+                                          BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+               if (++ring->start >= BGMAC_RX_RING_SLOTS)
+                       ring->start = 0;
+
+               if (handled >= weight) /* Should never be greater */
+                       break;
+       }
+
+       return handled;
+}
+
+/* Does ring support unaligned addressing? */
+static bool bgmac_dma_unaligned(struct bgmac *bgmac,
+                               struct bgmac_dma_ring *ring,
+                               enum bgmac_dma_ring_type ring_type)
+{
+       switch (ring_type) {
+       case BGMAC_DMA_RING_TX:
+               bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
+                           0xff0);
+               if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO))
+                       return true;
+               break;
+       case BGMAC_DMA_RING_RX:
+               bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
+                           0xff0);
+               if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO))
+                       return true;
+               break;
+       }
+       return false;
+}
+
+static void bgmac_dma_ring_free(struct bgmac *bgmac,
+                               struct bgmac_dma_ring *ring)
+{
+       struct device *dma_dev = bgmac->core->dma_dev;
+       struct bgmac_slot_info *slot;
+       int size;
+       int i;
+
+       for (i = 0; i < ring->num_slots; i++) {
+               slot = &ring->slots[i];
+               if (slot->skb) {
+                       if (slot->dma_addr)
+                               dma_unmap_single(dma_dev, slot->dma_addr,
+                                                slot->skb->len, DMA_TO_DEVICE);
+                       dev_kfree_skb(slot->skb);
+               }
+       }
+
+       if (ring->cpu_base) {
+               /* Free ring of descriptors */
+               size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+               dma_free_coherent(dma_dev, size, ring->cpu_base,
+                                 ring->dma_base);
+       }
+}
+
+static void bgmac_dma_free(struct bgmac *bgmac)
+{
+       int i;
+
+       for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+               bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]);
+       for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+               bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]);
+}
+
+static int bgmac_dma_alloc(struct bgmac *bgmac)
+{
+       struct device *dma_dev = bgmac->core->dma_dev;
+       struct bgmac_dma_ring *ring;
+       static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1,
+                                        BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, };
+       int size; /* ring size: different for Tx and Rx */
+       int err;
+       int i;
+
+       BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base));
+       BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
+
+       if (!(bcma_aread32(bgmac->core, BCMA_IOST) & BCMA_IOST_DMA64)) {
+               bgmac_err(bgmac, "Core does not report 64-bit DMA\n");
+               return -ENOTSUPP;
+       }
+
+       for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+               ring = &bgmac->tx_ring[i];
+               ring->num_slots = BGMAC_TX_RING_SLOTS;
+               ring->mmio_base = ring_base[i];
+               if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_TX))
+                       bgmac_warn(bgmac, "TX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
+                                  ring->mmio_base);
+
+               /* Alloc ring of descriptors */
+               size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+               ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+                                                    &ring->dma_base,
+                                                    GFP_KERNEL);
+               if (!ring->cpu_base) {
+                       bgmac_err(bgmac, "Allocation of TX ring 0x%X failed\n",
+                                 ring->mmio_base);
+                       goto err_dma_free;
+               }
+               if (ring->dma_base & 0xC0000000)
+                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+               /* No need to alloc TX slots yet */
+       }
+
+       for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+               ring = &bgmac->rx_ring[i];
+               ring->num_slots = BGMAC_RX_RING_SLOTS;
+               ring->mmio_base = ring_base[i];
+               if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_RX))
+                       bgmac_warn(bgmac, "RX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
+                                  ring->mmio_base);
+
+               /* Alloc ring of descriptors */
+               size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+               ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+                                                    &ring->dma_base,
+                                                    GFP_KERNEL);
+               if (!ring->cpu_base) {
+                       bgmac_err(bgmac, "Allocation of RX ring 0x%X failed\n",
+                                 ring->mmio_base);
+                       err = -ENOMEM;
+                       goto err_dma_free;
+               }
+               if (ring->dma_base & 0xC0000000)
+                       bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+               /* Alloc RX slots */
+               for (i = 0; i < ring->num_slots; i++) {
+                       err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[i]);
+                       if (err) {
+                               bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n");
+                               goto err_dma_free;
+                       }
+               }
+       }
+
+       return 0;
+
+err_dma_free:
+       bgmac_dma_free(bgmac);
+       return -ENOMEM;
+}
+
+static void bgmac_dma_init(struct bgmac *bgmac)
+{
+       struct bgmac_dma_ring *ring;
+       struct bgmac_dma_desc *dma_desc;
+       u32 ctl0, ctl1;
+       int i;
+
+       for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+               ring = &bgmac->tx_ring[i];
+
+               /* We don't implement unaligned addressing, so enable first */
+               bgmac_dma_tx_enable(bgmac, ring);
+               bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
+                           lower_32_bits(ring->dma_base));
+               bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGHI,
+                           upper_32_bits(ring->dma_base));
+
+               ring->start = 0;
+               ring->end = 0;  /* Points the slot that should *not* be read */
+       }
+
+       for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+               ring = &bgmac->rx_ring[i];
+
+               /* We don't implement unaligned addressing, so enable first */
+               bgmac_dma_rx_enable(bgmac, ring);
+               bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
+                           lower_32_bits(ring->dma_base));
+               bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI,
+                           upper_32_bits(ring->dma_base));
+
+               for (i = 0, dma_desc = ring->cpu_base; i < ring->num_slots;
+                    i++, dma_desc++) {
+                       ctl0 = ctl1 = 0;
+
+                       if (i == ring->num_slots - 1)
+                               ctl0 |= BGMAC_DESC_CTL0_EOT;
+                       ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN;
+                       /* Is there any BGMAC device that requires extension? */
+                       /* ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) &
+                        * B43_DMA64_DCTL1_ADDREXT_MASK;
+                        */
+
+                       dma_desc->addr_low = cpu_to_le32(lower_32_bits(ring->slots[i].dma_addr));
+                       dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[i].dma_addr));
+                       dma_desc->ctl0 = cpu_to_le32(ctl0);
+                       dma_desc->ctl1 = cpu_to_le32(ctl1);
+               }
+
+               bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
+                           ring->num_slots * sizeof(struct bgmac_dma_desc));
+
+               ring->start = 0;
+               ring->end = 0;
+       }
+}
+
+/**************************************************
+ * PHY ops
+ **************************************************/
+
+u16 bgmac_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
+{
+       struct bcma_device *core;
+       u16 phy_access_addr;
+       u16 phy_ctl_addr;
+       u32 tmp;
+
+       BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
+       BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
+       BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
+       BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
+       BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
+       BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
+       BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
+       BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
+       BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
+       BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
+       BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
+
+       if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+               core = bgmac->core->bus->drv_gmac_cmn.core;
+               phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+               phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+       } else {
+               core = bgmac->core;
+               phy_access_addr = BGMAC_PHY_ACCESS;
+               phy_ctl_addr = BGMAC_PHY_CNTL;
+       }
+
+       tmp = bcma_read32(core, phy_ctl_addr);
+       tmp &= ~BGMAC_PC_EPA_MASK;
+       tmp |= phyaddr;
+       bcma_write32(core, phy_ctl_addr, tmp);
+
+       tmp = BGMAC_PA_START;
+       tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+       tmp |= reg << BGMAC_PA_REG_SHIFT;
+       bcma_write32(core, phy_access_addr, tmp);
+
+       if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+               bgmac_err(bgmac, "Reading PHY %d register 0x%X failed\n",
+                         phyaddr, reg);
+               return 0xffff;
+       }
+
+       return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
+void bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value)
+{
+       struct bcma_device *core;
+       u16 phy_access_addr;
+       u16 phy_ctl_addr;
+       u32 tmp;
+
+       if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+               core = bgmac->core->bus->drv_gmac_cmn.core;
+               phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+               phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+       } else {
+               core = bgmac->core;
+               phy_access_addr = BGMAC_PHY_ACCESS;
+               phy_ctl_addr = BGMAC_PHY_CNTL;
+       }
+
+       tmp = bcma_read32(core, phy_ctl_addr);
+       tmp &= ~BGMAC_PC_EPA_MASK;
+       tmp |= phyaddr;
+       bcma_write32(core, phy_ctl_addr, tmp);
+
+       bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
+       if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
+               bgmac_warn(bgmac, "Error setting MDIO int\n");
+
+       tmp = BGMAC_PA_START;
+       tmp |= BGMAC_PA_WRITE;
+       tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+       tmp |= reg << BGMAC_PA_REG_SHIFT;
+       tmp |= value;
+       bcma_write32(core, phy_access_addr, tmp);
+
+       if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000))
+               bgmac_err(bgmac, "Writing to PHY %d register 0x%X failed\n",
+                         phyaddr, reg);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyforce */
+static void bgmac_phy_force(struct bgmac *bgmac)
+{
+       u16 ctl;
+       u16 mask = ~(BGMAC_PHY_CTL_SPEED | BGMAC_PHY_CTL_SPEED_MSB |
+                    BGMAC_PHY_CTL_ANENAB | BGMAC_PHY_CTL_DUPLEX);
+
+       if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+               return;
+
+       if (bgmac->autoneg)
+               return;
+
+       ctl = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL);
+       ctl &= mask;
+       if (bgmac->full_duplex)
+               ctl |= BGMAC_PHY_CTL_DUPLEX;
+       if (bgmac->speed == BGMAC_SPEED_100)
+               ctl |= BGMAC_PHY_CTL_SPEED_100;
+       else if (bgmac->speed == BGMAC_SPEED_1000)
+               ctl |= BGMAC_PHY_CTL_SPEED_1000;
+       bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, ctl);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyadvertise */
+static void bgmac_phy_advertise(struct bgmac *bgmac)
+{
+       u16 adv;
+
+       if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+               return;
+
+       if (!bgmac->autoneg)
+               return;
+
+       /* Adv selected 10/100 speeds */
+       adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV);
+       adv &= ~(BGMAC_PHY_ADV_10HALF | BGMAC_PHY_ADV_10FULL |
+                BGMAC_PHY_ADV_100HALF | BGMAC_PHY_ADV_100FULL);
+       if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
+               adv |= BGMAC_PHY_ADV_10HALF;
+       if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
+               adv |= BGMAC_PHY_ADV_100HALF;
+       if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
+               adv |= BGMAC_PHY_ADV_10FULL;
+       if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
+               adv |= BGMAC_PHY_ADV_100FULL;
+       bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV, adv);
+
+       /* Adv selected 1000 speeds */
+       adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2);
+       adv &= ~(BGMAC_PHY_ADV2_1000HALF | BGMAC_PHY_ADV2_1000FULL);
+       if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
+               adv |= BGMAC_PHY_ADV2_1000HALF;
+       if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
+               adv |= BGMAC_PHY_ADV2_1000FULL;
+       bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2, adv);
+
+       /* Restart */
+       bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL,
+                       bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) |
+                       BGMAC_PHY_CTL_RESTART);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
+static void bgmac_phy_init(struct bgmac *bgmac)
+{
+       struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+       struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+       u8 i;
+
+       if (ci->id == BCMA_CHIP_ID_BCM5356) {
+               for (i = 0; i < 5; i++) {
+                       bgmac_phy_write(bgmac, i, 0x1f, 0x008b);
+                       bgmac_phy_write(bgmac, i, 0x15, 0x0100);
+                       bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+                       bgmac_phy_write(bgmac, i, 0x12, 0x2aaa);
+                       bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+               }
+       }
+       if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
+           (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
+           (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
+               bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
+               bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
+               for (i = 0; i < 5; i++) {
+                       bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+                       bgmac_phy_write(bgmac, i, 0x16, 0x5284);
+                       bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+                       bgmac_phy_write(bgmac, i, 0x17, 0x0010);
+                       bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+                       bgmac_phy_write(bgmac, i, 0x16, 0x5296);
+                       bgmac_phy_write(bgmac, i, 0x17, 0x1073);
+                       bgmac_phy_write(bgmac, i, 0x17, 0x9073);
+                       bgmac_phy_write(bgmac, i, 0x16, 0x52b6);
+                       bgmac_phy_write(bgmac, i, 0x17, 0x9273);
+                       bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+               }
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
+static void bgmac_phy_reset(struct bgmac *bgmac)
+{
+       if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+               return;
+
+       bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL,
+                       BGMAC_PHY_CTL_RESET);
+       udelay(100);
+       if (bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) &
+           BGMAC_PHY_CTL_RESET)
+               bgmac_err(bgmac, "PHY reset failed\n");
+       bgmac_phy_init(bgmac);
+}
+
+/**************************************************
+ * Chip ops
+ **************************************************/
+
+/* TODO: can we just drop @force? Can we don't reset MAC at all if there is
+ * nothing to change? Try if after stabilizng driver.
+ */
+static void bgmac_cmdcfg_maskset(struct bgmac *bgmac, u32 mask, u32 set,
+                                bool force)
+{
+       u32 cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+       u32 new_val = (cmdcfg & mask) | set;
+
+       bgmac_set(bgmac, BGMAC_CMDCFG, BGMAC_CMDCFG_SR);
+       udelay(2);
+
+       if (new_val != cmdcfg || force)
+               bgmac_write(bgmac, BGMAC_CMDCFG, new_val);
+
+       bgmac_mask(bgmac, BGMAC_CMDCFG, ~BGMAC_CMDCFG_SR);
+       udelay(2);
+}
+
+#if 0 /* We don't use that regs yet */
+static void bgmac_chip_stats_update(struct bgmac *bgmac)
+{
+       int i;
+
+       if (bgmac->core->id.id != BCMA_CORE_4706_MAC_GBIT) {
+               for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
+                       bgmac->mib_tx_regs[i] =
+                               bgmac_read(bgmac,
+                                          BGMAC_TX_GOOD_OCTETS + (i * 4));
+               for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
+                       bgmac->mib_rx_regs[i] =
+                               bgmac_read(bgmac,
+                                          BGMAC_RX_GOOD_OCTETS + (i * 4));
+       }
+
+       /* TODO: what else? how to handle BCM4706? Specs are needed */
+}
+#endif
+
+static void bgmac_clear_mib(struct bgmac *bgmac)
+{
+       int i;
+
+       if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT)
+               return;
+
+       bgmac_set(bgmac, BGMAC_DEV_CTL, BGMAC_DC_MROR);
+       for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
+               bgmac_read(bgmac, BGMAC_TX_GOOD_OCTETS + (i * 4));
+       for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
+               bgmac_read(bgmac, BGMAC_RX_GOOD_OCTETS + (i * 4));
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */
+static void bgmac_speed(struct bgmac *bgmac, int speed)
+{
+       u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD);
+       u32 set = 0;
+
+       if (speed & BGMAC_SPEED_10)
+               set |= BGMAC_CMDCFG_ES_10;
+       if (speed & BGMAC_SPEED_100)
+               set |= BGMAC_CMDCFG_ES_100;
+       if (speed & BGMAC_SPEED_1000)
+               set |= BGMAC_CMDCFG_ES_1000;
+       if (!bgmac->full_duplex)
+               set |= BGMAC_CMDCFG_HD;
+       bgmac_cmdcfg_maskset(bgmac, mask, set, true);
+}
+
+static void bgmac_miiconfig(struct bgmac *bgmac)
+{
+       u8 imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+                       BGMAC_DS_MM_SHIFT;
+       if (imode == 0 || imode == 1) {
+               if (bgmac->autoneg)
+                       bgmac_speed(bgmac, BGMAC_SPEED_100);
+               else
+                       bgmac_speed(bgmac, bgmac->speed);
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */
+static void bgmac_chip_reset(struct bgmac *bgmac)
+{
+       struct bcma_device *core = bgmac->core;
+       struct bcma_bus *bus = core->bus;
+       struct bcma_chipinfo *ci = &bus->chipinfo;
+       u32 flags = 0;
+       u32 iost;
+       int i;
+
+       if (bcma_core_is_enabled(core)) {
+               if (!bgmac->stats_grabbed) {
+                       /* bgmac_chip_stats_update(bgmac); */
+                       bgmac->stats_grabbed = true;
+               }
+
+               for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+                       bgmac_dma_tx_reset(bgmac, &bgmac->tx_ring[i]);
+
+               bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false);
+               udelay(1);
+
+               for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+                       bgmac_dma_rx_reset(bgmac, &bgmac->rx_ring[i]);
+
+               /* TODO: Clear software multicast filter list */
+       }
+
+       iost = bcma_aread32(core, BCMA_IOST);
+       if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 10) ||
+           (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) ||
+           (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == 9))
+               iost &= ~BGMAC_BCMA_IOST_ATTACHED;
+
+       if (iost & BGMAC_BCMA_IOST_ATTACHED) {
+               flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
+               if (!bgmac->has_robosw)
+                       flags |= BGMAC_BCMA_IOCTL_SW_RESET;
+       }
+
+       bcma_core_enable(core, flags);
+
+       if (core->id.rev > 2) {
+               bgmac_set(bgmac, BCMA_CLKCTLST, 1 << 8);
+               bgmac_wait_value(bgmac->core, BCMA_CLKCTLST, 1 << 24, 1 << 24,
+                                1000);
+       }
+
+       if (ci->id == BCMA_CHIP_ID_BCM5357 || ci->id == BCMA_CHIP_ID_BCM4749 ||
+           ci->id == BCMA_CHIP_ID_BCM53572) {
+               struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+               u8 et_swtype = 0;
+               u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY |
+                            BGMAC_CHIPCTL_1_IF_TYPE_RMII;
+               char buf[2];
+
+               if (nvram_getenv("et_swtype", buf, 1) > 0) {
+                       if (kstrtou8(buf, 0, &et_swtype))
+                               bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
+                                         buf);
+                       et_swtype &= 0x0f;
+                       et_swtype <<= 4;
+                       sw_type = et_swtype;
+               } else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 9) {
+                       sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
+               } else if (0) {
+                       /* TODO */
+               }
+               bcma_chipco_chipctl_maskset(cc, 1,
+                                           ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK |
+                                             BGMAC_CHIPCTL_1_SW_TYPE_MASK),
+                                           sw_type);
+       }
+
+       if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
+               bcma_awrite32(core, BCMA_IOCTL,
+                             bcma_aread32(core, BCMA_IOCTL) &
+                             ~BGMAC_BCMA_IOCTL_SW_RESET);
+
+       /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_reset
+        * Specs don't say about using BGMAC_CMDCFG_SR, but in this routine
+        * BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to
+        * be keps until taking MAC out of the reset.
+        */
+       bgmac_cmdcfg_maskset(bgmac,
+                            ~(BGMAC_CMDCFG_TE |
+                              BGMAC_CMDCFG_RE |
+                              BGMAC_CMDCFG_RPI |
+                              BGMAC_CMDCFG_TAI |
+                              BGMAC_CMDCFG_HD |
+                              BGMAC_CMDCFG_ML |
+                              BGMAC_CMDCFG_CFE |
+                              BGMAC_CMDCFG_RL |
+                              BGMAC_CMDCFG_RED |
+                              BGMAC_CMDCFG_PE |
+                              BGMAC_CMDCFG_TPI |
+                              BGMAC_CMDCFG_PAD_EN |
+                              BGMAC_CMDCFG_PF),
+                            BGMAC_CMDCFG_PROM |
+                            BGMAC_CMDCFG_NLC |
+                            BGMAC_CMDCFG_CFE |
+                            BGMAC_CMDCFG_SR,
+                            false);
+
+       bgmac_clear_mib(bgmac);
+       if (core->id.id == BCMA_CORE_4706_MAC_GBIT)
+               bcma_maskset32(bgmac->cmn, BCMA_GMAC_CMN_PHY_CTL, ~0,
+                              BCMA_GMAC_CMN_PC_MTE);
+       else
+               bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE);
+       bgmac_miiconfig(bgmac);
+       bgmac_phy_init(bgmac);
+
+       bgmac->int_status = 0;
+}
+
+static void bgmac_chip_intrs_on(struct bgmac *bgmac)
+{
+       bgmac_write(bgmac, BGMAC_INT_MASK, bgmac->int_mask);
+}
+
+static void bgmac_chip_intrs_off(struct bgmac *bgmac)
+{
+       bgmac_write(bgmac, BGMAC_INT_MASK, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_enable */
+static void bgmac_enable(struct bgmac *bgmac)
+{
+       struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+       u32 cmdcfg;
+       u32 mode;
+       u32 rxq_ctl;
+       u32 fl_ctl;
+       u16 bp_clk;
+       u8 mdp;
+
+       cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+       bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE),
+                            BGMAC_CMDCFG_SR, true);
+       udelay(2);
+       cmdcfg |= BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE;
+       bgmac_write(bgmac, BGMAC_CMDCFG, cmdcfg);
+
+       mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+               BGMAC_DS_MM_SHIFT;
+       if (ci->id != BCMA_CHIP_ID_BCM47162 || mode != 0)
+               bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+       if (ci->id == BCMA_CHIP_ID_BCM47162 && mode == 2)
+               bcma_chipco_chipctl_maskset(&bgmac->core->bus->drv_cc, 1, ~0,
+                                           BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
+
+       switch (ci->id) {
+       case BCMA_CHIP_ID_BCM5357:
+       case BCMA_CHIP_ID_BCM4749:
+       case BCMA_CHIP_ID_BCM53572:
+       case BCMA_CHIP_ID_BCM4716:
+       case BCMA_CHIP_ID_BCM47162:
+               fl_ctl = 0x03cb04cb;
+               if (ci->id == BCMA_CHIP_ID_BCM5357 ||
+                   ci->id == BCMA_CHIP_ID_BCM4749 ||
+                   ci->id == BCMA_CHIP_ID_BCM53572)
+                       fl_ctl = 0x2300e1;
+               bgmac_write(bgmac, BGMAC_FLOW_CTL_THRESH, fl_ctl);
+               bgmac_write(bgmac, BGMAC_PAUSE_CTL, 0x27fff);
+               break;
+       }
+
+       rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
+       rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
+       bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) / 1000000;
+       mdp = (bp_clk * 128 / 1000) - 3;
+       rxq_ctl |= (mdp << BGMAC_RXQ_CTL_MDP_SHIFT);
+       bgmac_write(bgmac, BGMAC_RXQ_CTL, rxq_ctl);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
+static void bgmac_chip_init(struct bgmac *bgmac, bool full_init)
+{
+       struct bgmac_dma_ring *ring;
+       u8 *mac = bgmac->net_dev->dev_addr;
+       u32 tmp;
+       int i;
+
+       /* 1 interrupt per received frame */
+       bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
+
+       /* Enable 802.3x tx flow control (honor received PAUSE frames) */
+       bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_RPI, 0, true);
+
+       if (bgmac->net_dev->flags & IFF_PROMISC)
+               bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_PROM, false);
+       else
+               bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_PROM, 0, false);
+
+       /* Set MAC addr */
+       tmp = (mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | mac[3];
+       bgmac_write(bgmac, BGMAC_MACADDR_HIGH, tmp);
+       tmp = (mac[4] << 8) | mac[5];
+       bgmac_write(bgmac, BGMAC_MACADDR_LOW, tmp);
+
+       if (bgmac->loopback)
+               bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, true);
+       else
+               bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_ML, 0, true);
+
+       bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN);
+
+       if (!bgmac->autoneg) {
+               bgmac_speed(bgmac, bgmac->speed);
+               bgmac_phy_force(bgmac);
+       } else if (bgmac->speed) { /* if there is anything to adv */
+               bgmac_phy_advertise(bgmac);
+       }
+
+       if (full_init) {
+               bgmac_dma_init(bgmac);
+               if (1) /* FIXME: is there any case we don't want IRQs? */
+                       bgmac_chip_intrs_on(bgmac);
+       } else {
+               for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+                       ring = &bgmac->rx_ring[i];
+                       bgmac_dma_rx_enable(bgmac, ring);
+               }
+       }
+
+       bgmac_enable(bgmac);
+}
+
+static irqreturn_t bgmac_interrupt(int irq, void *dev_id)
+{
+       struct bgmac *bgmac = netdev_priv(dev_id);
+
+       u32 int_status = bgmac_read(bgmac, BGMAC_INT_STATUS);
+       int_status &= bgmac->int_mask;
+
+       if (!int_status)
+               return IRQ_NONE;
+
+       /* Ack */
+       bgmac_write(bgmac, BGMAC_INT_STATUS, int_status);
+
+       /* Disable new interrupts until handling existing ones */
+       bgmac_chip_intrs_off(bgmac);
+
+       bgmac->int_status = int_status;
+
+       napi_schedule(&bgmac->napi);
+
+       return IRQ_HANDLED;
+}
+
+static int bgmac_poll(struct napi_struct *napi, int weight)
+{
+       struct bgmac *bgmac = container_of(napi, struct bgmac, napi);
+       struct bgmac_dma_ring *ring;
+       int handled = 0;
+
+       if (bgmac->int_status & BGMAC_IS_TX0) {
+               ring = &bgmac->tx_ring[0];
+               bgmac_dma_tx_free(bgmac, ring);
+               bgmac->int_status &= ~BGMAC_IS_TX0;
+       }
+
+       if (bgmac->int_status & BGMAC_IS_RX) {
+               ring = &bgmac->rx_ring[0];
+               handled += bgmac_dma_rx_read(bgmac, ring, weight);
+               bgmac->int_status &= ~BGMAC_IS_RX;
+       }
+
+       if (bgmac->int_status) {
+               bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status);
+               bgmac->int_status = 0;
+       }
+
+       if (handled < weight)
+               napi_complete(napi);
+
+       bgmac_chip_intrs_on(bgmac);
+
+       return handled;
+}
+
+/**************************************************
+ * net_device_ops
+ **************************************************/
+
+static int bgmac_open(struct net_device *net_dev)
+{
+       struct bgmac *bgmac = netdev_priv(net_dev);
+       int err = 0;
+
+       bgmac_chip_reset(bgmac);
+       /* Specs say about reclaiming rings here, but we do that in DMA init */
+       bgmac_chip_init(bgmac, true);
+
+       err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
+                         KBUILD_MODNAME, net_dev);
+       if (err < 0) {
+               bgmac_err(bgmac, "IRQ request error: %d!\n", err);
+               goto err_out;
+       }
+       napi_enable(&bgmac->napi);
+
+       netif_carrier_on(net_dev);
+
+err_out:
+       return err;
+}
+
+static int bgmac_stop(struct net_device *net_dev)
+{
+       struct bgmac *bgmac = netdev_priv(net_dev);
+
+       netif_carrier_off(net_dev);
+
+       napi_disable(&bgmac->napi);
+       bgmac_chip_intrs_off(bgmac);
+       free_irq(bgmac->core->irq, net_dev);
+
+       bgmac_chip_reset(bgmac);
+
+       return 0;
+}
+
+static netdev_tx_t bgmac_start_xmit(struct sk_buff *skb,
+                                   struct net_device *net_dev)
+{
+       struct bgmac *bgmac = netdev_priv(net_dev);
+       struct bgmac_dma_ring *ring;
+
+       /* No QOS support yet */
+       ring = &bgmac->tx_ring[0];
+       return bgmac_dma_tx_add(bgmac, ring, skb);
+}
+
+static int bgmac_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+{
+       struct bgmac *bgmac = netdev_priv(net_dev);
+       struct mii_ioctl_data *data = if_mii(ifr);
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               data->phy_id = bgmac->phyaddr;
+               /* fallthru */
+       case SIOCGMIIREG:
+               if (!netif_running(net_dev))
+                       return -EAGAIN;
+               data->val_out = bgmac_phy_read(bgmac, data->phy_id,
+                                              data->reg_num & 0x1f);
+               return 0;
+       case SIOCSMIIREG:
+               if (!netif_running(net_dev))
+                       return -EAGAIN;
+               bgmac_phy_write(bgmac, data->phy_id, data->reg_num & 0x1f,
+                               data->val_in);
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static const struct net_device_ops bgmac_netdev_ops = {
+       .ndo_open               = bgmac_open,
+       .ndo_stop               = bgmac_stop,
+       .ndo_start_xmit         = bgmac_start_xmit,
+       .ndo_set_mac_address    = eth_mac_addr, /* generic, sets dev_addr */
+       .ndo_do_ioctl           = bgmac_ioctl,
+};
+
+/**************************************************
+ * ethtool_ops
+ **************************************************/
+
+static int bgmac_get_settings(struct net_device *net_dev,
+                             struct ethtool_cmd *cmd)
+{
+       struct bgmac *bgmac = netdev_priv(net_dev);
+
+       cmd->supported = SUPPORTED_10baseT_Half |
+                        SUPPORTED_10baseT_Full |
+                        SUPPORTED_100baseT_Half |
+                        SUPPORTED_100baseT_Full |
+                        SUPPORTED_1000baseT_Half |
+                        SUPPORTED_1000baseT_Full |
+                        SUPPORTED_Autoneg;
+
+       if (bgmac->autoneg) {
+               WARN_ON(cmd->advertising);
+               if (bgmac->full_duplex) {
+                       if (bgmac->speed & BGMAC_SPEED_10)
+                               cmd->advertising |= ADVERTISED_10baseT_Full;
+                       if (bgmac->speed & BGMAC_SPEED_100)
+                               cmd->advertising |= ADVERTISED_100baseT_Full;
+                       if (bgmac->speed & BGMAC_SPEED_1000)
+                               cmd->advertising |= ADVERTISED_1000baseT_Full;
+               } else {
+                       if (bgmac->speed & BGMAC_SPEED_10)
+                               cmd->advertising |= ADVERTISED_10baseT_Half;
+                       if (bgmac->speed & BGMAC_SPEED_100)
+                               cmd->advertising |= ADVERTISED_100baseT_Half;
+                       if (bgmac->speed & BGMAC_SPEED_1000)
+                               cmd->advertising |= ADVERTISED_1000baseT_Half;
+               }
+       } else {
+               switch (bgmac->speed) {
+               case BGMAC_SPEED_10:
+                       ethtool_cmd_speed_set(cmd, SPEED_10);
+                       break;
+               case BGMAC_SPEED_100:
+                       ethtool_cmd_speed_set(cmd, SPEED_100);
+                       break;
+               case BGMAC_SPEED_1000:
+                       ethtool_cmd_speed_set(cmd, SPEED_1000);
+                       break;
+               }
+       }
+
+       cmd->duplex = bgmac->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+
+       cmd->autoneg = bgmac->autoneg;
+
+       return 0;
+}
+
+#if 0
+static int bgmac_set_settings(struct net_device *net_dev,
+                             struct ethtool_cmd *cmd)
+{
+       struct bgmac *bgmac = netdev_priv(net_dev);
+
+       return -1;
+}
+#endif
+
+static void bgmac_get_drvinfo(struct net_device *net_dev,
+                             struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->bus_info, "BCMA", sizeof(info->bus_info));
+}
+
+static const struct ethtool_ops bgmac_ethtool_ops = {
+       .get_settings           = bgmac_get_settings,
+       .get_drvinfo            = bgmac_get_drvinfo,
+};
+
+/**************************************************
+ * BCMA bus ops
+ **************************************************/
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
+static int bgmac_probe(struct bcma_device *core)
+{
+       struct net_device *net_dev;
+       struct bgmac *bgmac;
+       struct ssb_sprom *sprom = &core->bus->sprom;
+       u8 *mac = core->core_unit ? sprom->et1mac : sprom->et0mac;
+       int err;
+
+       /* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */
+       if (core->core_unit > 1) {
+               pr_err("Unsupported core_unit %d\n", core->core_unit);
+               return -ENOTSUPP;
+       }
+
+       /* Allocation and references */
+       net_dev = alloc_etherdev(sizeof(*bgmac));
+       if (!net_dev)
+               return -ENOMEM;
+       net_dev->netdev_ops = &bgmac_netdev_ops;
+       net_dev->irq = core->irq;
+       SET_ETHTOOL_OPS(net_dev, &bgmac_ethtool_ops);
+       bgmac = netdev_priv(net_dev);
+       bgmac->net_dev = net_dev;
+       bgmac->core = core;
+       bcma_set_drvdata(core, bgmac);
+
+       /* Defaults */
+       bgmac->autoneg = true;
+       bgmac->full_duplex = true;
+       bgmac->speed = BGMAC_SPEED_10 | BGMAC_SPEED_100 | BGMAC_SPEED_1000;
+       memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN);
+
+       /* On BCM4706 we need common core to access PHY */
+       if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
+           !core->bus->drv_gmac_cmn.core) {
+               bgmac_err(bgmac, "GMAC CMN core not found (required for BCM4706)\n");
+               err = -ENODEV;
+               goto err_netdev_free;
+       }
+       bgmac->cmn = core->bus->drv_gmac_cmn.core;
+
+       bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr :
+                        sprom->et0phyaddr;
+       bgmac->phyaddr &= BGMAC_PHY_MASK;
+       if (bgmac->phyaddr == BGMAC_PHY_MASK) {
+               bgmac_err(bgmac, "No PHY found\n");
+               err = -ENODEV;
+               goto err_netdev_free;
+       }
+       bgmac_info(bgmac, "Found PHY addr: %d%s\n", bgmac->phyaddr,
+                  bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
+
+       if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
+               bgmac_err(bgmac, "PCI setup not implemented\n");
+               err = -ENOTSUPP;
+               goto err_netdev_free;
+       }
+
+       bgmac_chip_reset(bgmac);
+
+       err = bgmac_dma_alloc(bgmac);
+       if (err) {
+               bgmac_err(bgmac, "Unable to alloc memory for DMA\n");
+               goto err_netdev_free;
+       }
+
+       bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
+       if (nvram_getenv("et0_no_txint", NULL, 0) == 0)
+               bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
+
+       /* TODO: reset the external phy. Specs are needed */
+       bgmac_phy_reset(bgmac);
+
+       bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
+                              BGMAC_BFL_ENETROBO);
+       if (bgmac->has_robosw)
+               bgmac_warn(bgmac, "Support for Roboswitch not implemented\n");
+
+       if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
+               bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
+
+       err = register_netdev(bgmac->net_dev);
+       if (err) {
+               bgmac_err(bgmac, "Cannot register net device\n");
+               err = -ENOTSUPP;
+               goto err_dma_free;
+       }
+
+       netif_carrier_off(net_dev);
+
+       netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+
+       return 0;
+
+err_dma_free:
+       bgmac_dma_free(bgmac);
+
+err_netdev_free:
+       bcma_set_drvdata(core, NULL);
+       free_netdev(net_dev);
+
+       return err;
+}
+
+static void bgmac_remove(struct bcma_device *core)
+{
+       struct bgmac *bgmac = bcma_get_drvdata(core);
+
+       netif_napi_del(&bgmac->napi);
+       unregister_netdev(bgmac->net_dev);
+       bgmac_dma_free(bgmac);
+       bcma_set_drvdata(core, NULL);
+       free_netdev(bgmac->net_dev);
+}
+
+static struct bcma_driver bgmac_bcma_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = bgmac_bcma_tbl,
+       .probe          = bgmac_probe,
+       .remove         = bgmac_remove,
+};
+
+static int __init bgmac_init(void)
+{
+       int err;
+
+       err = bcma_driver_register(&bgmac_bcma_driver);
+       if (err)
+               return err;
+       pr_info("Broadcom 47xx GBit MAC driver loaded\n");
+
+       return 0;
+}
+
+static void __exit bgmac_exit(void)
+{
+       bcma_driver_unregister(&bgmac_bcma_driver);
+}
+
+module_init(bgmac_init)
+module_exit(bgmac_exit)
+
+MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
new file mode 100644 (file)
index 0000000..1299470
--- /dev/null
@@ -0,0 +1,456 @@
+#ifndef _BGMAC_H
+#define _BGMAC_H
+
+#define pr_fmt(fmt)            KBUILD_MODNAME ": " fmt
+
+#define bgmac_err(bgmac, fmt, ...) \
+       dev_err(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+#define bgmac_warn(bgmac, fmt, ...) \
+       dev_warn(&(bgmac)->core->dev, fmt,  ##__VA_ARGS__)
+#define bgmac_info(bgmac, fmt, ...) \
+       dev_info(&(bgmac)->core->dev, fmt,  ##__VA_ARGS__)
+#define bgmac_dbg(bgmac, fmt, ...) \
+       dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+
+#include <linux/bcma/bcma.h>
+#include <linux/netdevice.h>
+
+#define BGMAC_DEV_CTL                          0x000
+#define  BGMAC_DC_TSM                          0x00000002
+#define  BGMAC_DC_CFCO                         0x00000004
+#define  BGMAC_DC_RLSS                         0x00000008
+#define  BGMAC_DC_MROR                         0x00000010
+#define  BGMAC_DC_FCM_MASK                     0x00000060
+#define  BGMAC_DC_FCM_SHIFT                    5
+#define  BGMAC_DC_NAE                          0x00000080
+#define  BGMAC_DC_TF                           0x00000100
+#define  BGMAC_DC_RDS_MASK                     0x00030000
+#define  BGMAC_DC_RDS_SHIFT                    16
+#define  BGMAC_DC_TDS_MASK                     0x000c0000
+#define  BGMAC_DC_TDS_SHIFT                    18
+#define BGMAC_DEV_STATUS                       0x004           /* Configuration of the interface */
+#define  BGMAC_DS_RBF                          0x00000001
+#define  BGMAC_DS_RDF                          0x00000002
+#define  BGMAC_DS_RIF                          0x00000004
+#define  BGMAC_DS_TBF                          0x00000008
+#define  BGMAC_DS_TDF                          0x00000010
+#define  BGMAC_DS_TIF                          0x00000020
+#define  BGMAC_DS_PO                           0x00000040
+#define  BGMAC_DS_MM_MASK                      0x00000300      /* Mode of the interface */
+#define  BGMAC_DS_MM_SHIFT                     8
+#define BGMAC_BIST_STATUS                      0x00c
+#define BGMAC_INT_STATUS                       0x020           /* Interrupt status */
+#define  BGMAC_IS_MRO                          0x00000001
+#define  BGMAC_IS_MTO                          0x00000002
+#define  BGMAC_IS_TFD                          0x00000004
+#define  BGMAC_IS_LS                           0x00000008
+#define  BGMAC_IS_MDIO                         0x00000010
+#define  BGMAC_IS_MR                           0x00000020
+#define  BGMAC_IS_MT                           0x00000040
+#define  BGMAC_IS_TO                           0x00000080
+#define  BGMAC_IS_DESC_ERR                     0x00000400      /* Descriptor error */
+#define  BGMAC_IS_DATA_ERR                     0x00000800      /* Data error */
+#define  BGMAC_IS_DESC_PROT_ERR                        0x00001000      /* Descriptor protocol error */
+#define  BGMAC_IS_RX_DESC_UNDERF               0x00002000      /* Receive descriptor underflow */
+#define  BGMAC_IS_RX_F_OVERF                   0x00004000      /* Receive FIFO overflow */
+#define  BGMAC_IS_TX_F_UNDERF                  0x00008000      /* Transmit FIFO underflow */
+#define  BGMAC_IS_RX                           0x00010000      /* Interrupt for RX queue 0 */
+#define  BGMAC_IS_TX0                          0x01000000      /* Interrupt for TX queue 0 */
+#define  BGMAC_IS_TX1                          0x02000000      /* Interrupt for TX queue 1 */
+#define  BGMAC_IS_TX2                          0x04000000      /* Interrupt for TX queue 2 */
+#define  BGMAC_IS_TX3                          0x08000000      /* Interrupt for TX queue 3 */
+#define  BGMAC_IS_TX_MASK                      0x0f000000
+#define  BGMAC_IS_INTMASK                      0x0f01fcff
+#define  BGMAC_IS_ERRMASK                      0x0000fc00
+#define BGMAC_INT_MASK                         0x024           /* Interrupt mask */
+#define BGMAC_GP_TIMER                         0x028
+#define BGMAC_INT_RECV_LAZY                    0x100
+#define  BGMAC_IRL_TO_MASK                     0x00ffffff
+#define  BGMAC_IRL_FC_MASK                     0xff000000
+#define  BGMAC_IRL_FC_SHIFT                    24              /* Shift the number of interrupts triggered per received frame */
+#define BGMAC_FLOW_CTL_THRESH                  0x104           /* Flow control thresholds */
+#define BGMAC_WRRTHRESH                                0x108
+#define BGMAC_GMAC_IDLE_CNT_THRESH             0x10c
+#define BGMAC_PHY_ACCESS                       0x180           /* PHY access address */
+#define  BGMAC_PA_DATA_MASK                    0x0000ffff
+#define  BGMAC_PA_ADDR_MASK                    0x001f0000
+#define  BGMAC_PA_ADDR_SHIFT                   16
+#define  BGMAC_PA_REG_MASK                     0x1f000000
+#define  BGMAC_PA_REG_SHIFT                    24
+#define  BGMAC_PA_WRITE                                0x20000000
+#define  BGMAC_PA_START                                0x40000000
+#define BGMAC_PHY_CNTL                         0x188           /* PHY control address */
+#define  BGMAC_PC_EPA_MASK                     0x0000001f
+#define  BGMAC_PC_MCT_MASK                     0x007f0000
+#define  BGMAC_PC_MCT_SHIFT                    16
+#define  BGMAC_PC_MTE                          0x00800000
+#define BGMAC_TXQ_CTL                          0x18c
+#define  BGMAC_TXQ_CTL_DBT_MASK                        0x00000fff
+#define  BGMAC_TXQ_CTL_DBT_SHIFT               0
+#define BGMAC_RXQ_CTL                          0x190
+#define  BGMAC_RXQ_CTL_DBT_MASK                        0x00000fff
+#define  BGMAC_RXQ_CTL_DBT_SHIFT               0
+#define  BGMAC_RXQ_CTL_PTE                     0x00001000
+#define  BGMAC_RXQ_CTL_MDP_MASK                        0x3f000000
+#define  BGMAC_RXQ_CTL_MDP_SHIFT               24
+#define BGMAC_GPIO_SELECT                      0x194
+#define BGMAC_GPIO_OUTPUT_EN                   0x198
+/* For 0x1e0 see BCMA_CLKCTLST */
+#define BGMAC_HW_WAR                           0x1e4
+#define BGMAC_PWR_CTL                          0x1e8
+#define BGMAC_DMA_BASE0                                0x200           /* Tx and Rx controller */
+#define BGMAC_DMA_BASE1                                0x240           /* Tx controller only */
+#define BGMAC_DMA_BASE2                                0x280           /* Tx controller only */
+#define BGMAC_DMA_BASE3                                0x2C0           /* Tx controller only */
+#define BGMAC_TX_GOOD_OCTETS                   0x300
+#define BGMAC_TX_GOOD_OCTETS_HIGH              0x304
+#define BGMAC_TX_GOOD_PKTS                     0x308
+#define BGMAC_TX_OCTETS                                0x30c
+#define BGMAC_TX_OCTETS_HIGH                   0x310
+#define BGMAC_TX_PKTS                          0x314
+#define BGMAC_TX_BROADCAST_PKTS                        0x318
+#define BGMAC_TX_MULTICAST_PKTS                        0x31c
+#define BGMAC_TX_LEN_64                                0x320
+#define BGMAC_TX_LEN_65_TO_127                 0x324
+#define BGMAC_TX_LEN_128_TO_255                        0x328
+#define BGMAC_TX_LEN_256_TO_511                        0x32c
+#define BGMAC_TX_LEN_512_TO_1023               0x330
+#define BGMAC_TX_LEN_1024_TO_1522              0x334
+#define BGMAC_TX_LEN_1523_TO_2047              0x338
+#define BGMAC_TX_LEN_2048_TO_4095              0x33c
+#define BGMAC_TX_LEN_4095_TO_8191              0x340
+#define BGMAC_TX_LEN_8192_TO_MAX               0x344
+#define BGMAC_TX_JABBER_PKTS                   0x348           /* Error */
+#define BGMAC_TX_OVERSIZE_PKTS                 0x34c           /* Error */
+#define BGMAC_TX_FRAGMENT_PKTS                 0x350
+#define BGMAC_TX_UNDERRUNS                     0x354           /* Error */
+#define BGMAC_TX_TOTAL_COLS                    0x358
+#define BGMAC_TX_SINGLE_COLS                   0x35c
+#define BGMAC_TX_MULTIPLE_COLS                 0x360
+#define BGMAC_TX_EXCESSIVE_COLS                        0x364           /* Error */
+#define BGMAC_TX_LATE_COLS                     0x368           /* Error */
+#define BGMAC_TX_DEFERED                       0x36c
+#define BGMAC_TX_CARRIER_LOST                  0x370
+#define BGMAC_TX_PAUSE_PKTS                    0x374
+#define BGMAC_TX_UNI_PKTS                      0x378
+#define BGMAC_TX_Q0_PKTS                       0x37c
+#define BGMAC_TX_Q0_OCTETS                     0x380
+#define BGMAC_TX_Q0_OCTETS_HIGH                        0x384
+#define BGMAC_TX_Q1_PKTS                       0x388
+#define BGMAC_TX_Q1_OCTETS                     0x38c
+#define BGMAC_TX_Q1_OCTETS_HIGH                        0x390
+#define BGMAC_TX_Q2_PKTS                       0x394
+#define BGMAC_TX_Q2_OCTETS                     0x398
+#define BGMAC_TX_Q2_OCTETS_HIGH                        0x39c
+#define BGMAC_TX_Q3_PKTS                       0x3a0
+#define BGMAC_TX_Q3_OCTETS                     0x3a4
+#define BGMAC_TX_Q3_OCTETS_HIGH                        0x3a8
+#define BGMAC_RX_GOOD_OCTETS                   0x3b0
+#define BGMAC_RX_GOOD_OCTETS_HIGH              0x3b4
+#define BGMAC_RX_GOOD_PKTS                     0x3b8
+#define BGMAC_RX_OCTETS                                0x3bc
+#define BGMAC_RX_OCTETS_HIGH                   0x3c0
+#define BGMAC_RX_PKTS                          0x3c4
+#define BGMAC_RX_BROADCAST_PKTS                        0x3c8
+#define BGMAC_RX_MULTICAST_PKTS                        0x3cc
+#define BGMAC_RX_LEN_64                                0x3d0
+#define BGMAC_RX_LEN_65_TO_127                 0x3d4
+#define BGMAC_RX_LEN_128_TO_255                        0x3d8
+#define BGMAC_RX_LEN_256_TO_511                        0x3dc
+#define BGMAC_RX_LEN_512_TO_1023               0x3e0
+#define BGMAC_RX_LEN_1024_TO_1522              0x3e4
+#define BGMAC_RX_LEN_1523_TO_2047              0x3e8
+#define BGMAC_RX_LEN_2048_TO_4095              0x3ec
+#define BGMAC_RX_LEN_4095_TO_8191              0x3f0
+#define BGMAC_RX_LEN_8192_TO_MAX               0x3f4
+#define BGMAC_RX_JABBER_PKTS                   0x3f8           /* Error */
+#define BGMAC_RX_OVERSIZE_PKTS                 0x3fc           /* Error */
+#define BGMAC_RX_FRAGMENT_PKTS                 0x400
+#define BGMAC_RX_MISSED_PKTS                   0x404           /* Error */
+#define BGMAC_RX_CRC_ALIGN_ERRS                        0x408           /* Error */
+#define BGMAC_RX_UNDERSIZE                     0x40c           /* Error */
+#define BGMAC_RX_CRC_ERRS                      0x410           /* Error */
+#define BGMAC_RX_ALIGN_ERRS                    0x414           /* Error */
+#define BGMAC_RX_SYMBOL_ERRS                   0x418           /* Error */
+#define BGMAC_RX_PAUSE_PKTS                    0x41c
+#define BGMAC_RX_NONPAUSE_PKTS                 0x420
+#define BGMAC_RX_SACHANGES                     0x424
+#define BGMAC_RX_UNI_PKTS                      0x428
+#define BGMAC_UNIMAC_VERSION                   0x800
+#define BGMAC_HDBKP_CTL                                0x804
+#define BGMAC_CMDCFG                           0x808           /* Configuration */
+#define  BGMAC_CMDCFG_TE                       0x00000001      /* Set to activate TX */
+#define  BGMAC_CMDCFG_RE                       0x00000002      /* Set to activate RX */
+#define  BGMAC_CMDCFG_ES_MASK                  0x0000000c      /* Ethernet speed see gmac_speed */
+#define   BGMAC_CMDCFG_ES_10                   0x00000000
+#define   BGMAC_CMDCFG_ES_100                  0x00000004
+#define   BGMAC_CMDCFG_ES_1000                 0x00000008
+#define  BGMAC_CMDCFG_PROM                     0x00000010      /* Set to activate promiscuous mode */
+#define  BGMAC_CMDCFG_PAD_EN                   0x00000020
+#define  BGMAC_CMDCFG_CF                       0x00000040
+#define  BGMAC_CMDCFG_PF                       0x00000080
+#define  BGMAC_CMDCFG_RPI                      0x00000100      /* Unset to enable 802.3x tx flow control */
+#define  BGMAC_CMDCFG_TAI                      0x00000200
+#define  BGMAC_CMDCFG_HD                       0x00000400      /* Set if in half duplex mode */
+#define  BGMAC_CMDCFG_HD_SHIFT                 10
+#define  BGMAC_CMDCFG_SR                       0x00000800      /* Set to reset mode */
+#define  BGMAC_CMDCFG_ML                       0x00008000      /* Set to activate mac loopback mode */
+#define  BGMAC_CMDCFG_AE                       0x00400000
+#define  BGMAC_CMDCFG_CFE                      0x00800000
+#define  BGMAC_CMDCFG_NLC                      0x01000000
+#define  BGMAC_CMDCFG_RL                       0x02000000
+#define  BGMAC_CMDCFG_RED                      0x04000000
+#define  BGMAC_CMDCFG_PE                       0x08000000
+#define  BGMAC_CMDCFG_TPI                      0x10000000
+#define  BGMAC_CMDCFG_AT                       0x20000000
+#define BGMAC_MACADDR_HIGH                     0x80c           /* High 4 octets of own mac address */
+#define BGMAC_MACADDR_LOW                      0x810           /* Low 2 octets of own mac address */
+#define BGMAC_RXMAX_LENGTH                     0x814           /* Max receive frame length with vlan tag */
+#define BGMAC_PAUSEQUANTA                      0x818
+#define BGMAC_MAC_MODE                         0x844
+#define BGMAC_OUTERTAG                         0x848
+#define BGMAC_INNERTAG                         0x84c
+#define BGMAC_TXIPG                            0x85c
+#define BGMAC_PAUSE_CTL                                0xb30
+#define BGMAC_TX_FLUSH                         0xb34
+#define BGMAC_RX_STATUS                                0xb38
+#define BGMAC_TX_STATUS                                0xb3c
+
+#define BGMAC_PHY_CTL                          0x00
+#define  BGMAC_PHY_CTL_SPEED_MSB               0x0040
+#define  BGMAC_PHY_CTL_DUPLEX                  0x0100          /* duplex mode */
+#define  BGMAC_PHY_CTL_RESTART                 0x0200          /* restart autonegotiation */
+#define  BGMAC_PHY_CTL_ANENAB                  0x1000          /* enable autonegotiation */
+#define  BGMAC_PHY_CTL_SPEED                   0x2000
+#define  BGMAC_PHY_CTL_LOOP                    0x4000          /* loopback */
+#define  BGMAC_PHY_CTL_RESET                   0x8000          /* reset */
+/* Helpers */
+#define  BGMAC_PHY_CTL_SPEED_10                        0
+#define  BGMAC_PHY_CTL_SPEED_100               BGMAC_PHY_CTL_SPEED
+#define  BGMAC_PHY_CTL_SPEED_1000              BGMAC_PHY_CTL_SPEED_MSB
+#define BGMAC_PHY_ADV                          0x04
+#define  BGMAC_PHY_ADV_10HALF                  0x0020          /* advertise 10MBits/s half duplex */
+#define  BGMAC_PHY_ADV_10FULL                  0x0040          /* advertise 10MBits/s full duplex */
+#define  BGMAC_PHY_ADV_100HALF                 0x0080          /* advertise 100MBits/s half duplex */
+#define  BGMAC_PHY_ADV_100FULL                 0x0100          /* advertise 100MBits/s full duplex */
+#define BGMAC_PHY_ADV2                         0x09
+#define  BGMAC_PHY_ADV2_1000HALF               0x0100          /* advertise 1000MBits/s half duplex */
+#define  BGMAC_PHY_ADV2_1000FULL               0x0200          /* advertise 1000MBits/s full duplex */
+
+/* BCMA GMAC core specific IO Control (BCMA_IOCTL) flags */
+#define BGMAC_BCMA_IOCTL_SW_CLKEN              0x00000004      /* PHY Clock Enable */
+#define BGMAC_BCMA_IOCTL_SW_RESET              0x00000008      /* PHY Reset */
+
+/* BCMA GMAC core specific IO status (BCMA_IOST) flags */
+#define BGMAC_BCMA_IOST_ATTACHED               0x00000800
+
+#define BGMAC_NUM_MIB_TX_REGS  \
+               (((BGMAC_TX_Q3_OCTETS_HIGH - BGMAC_TX_GOOD_OCTETS) / 4) + 1)
+#define BGMAC_NUM_MIB_RX_REGS  \
+               (((BGMAC_RX_UNI_PKTS - BGMAC_RX_GOOD_OCTETS) / 4) + 1)
+
+#define BGMAC_DMA_TX_CTL                       0x00
+#define  BGMAC_DMA_TX_ENABLE                   0x00000001
+#define  BGMAC_DMA_TX_SUSPEND                  0x00000002
+#define  BGMAC_DMA_TX_LOOPBACK                 0x00000004
+#define  BGMAC_DMA_TX_FLUSH                    0x00000010
+#define  BGMAC_DMA_TX_PARITY_DISABLE           0x00000800
+#define  BGMAC_DMA_TX_ADDREXT_MASK             0x00030000
+#define  BGMAC_DMA_TX_ADDREXT_SHIFT            16
+#define BGMAC_DMA_TX_INDEX                     0x04
+#define BGMAC_DMA_TX_RINGLO                    0x08
+#define BGMAC_DMA_TX_RINGHI                    0x0C
+#define BGMAC_DMA_TX_STATUS                    0x10
+#define  BGMAC_DMA_TX_STATDPTR                 0x00001FFF
+#define  BGMAC_DMA_TX_STAT                     0xF0000000
+#define   BGMAC_DMA_TX_STAT_DISABLED           0x00000000
+#define   BGMAC_DMA_TX_STAT_ACTIVE             0x10000000
+#define   BGMAC_DMA_TX_STAT_IDLEWAIT           0x20000000
+#define   BGMAC_DMA_TX_STAT_STOPPED            0x30000000
+#define   BGMAC_DMA_TX_STAT_SUSP               0x40000000
+#define BGMAC_DMA_TX_ERROR                     0x14
+#define  BGMAC_DMA_TX_ERRDPTR                  0x0001FFFF
+#define  BGMAC_DMA_TX_ERR                      0xF0000000
+#define   BGMAC_DMA_TX_ERR_NOERR               0x00000000
+#define   BGMAC_DMA_TX_ERR_PROT                        0x10000000
+#define   BGMAC_DMA_TX_ERR_UNDERRUN            0x20000000
+#define   BGMAC_DMA_TX_ERR_TRANSFER            0x30000000
+#define   BGMAC_DMA_TX_ERR_DESCREAD            0x40000000
+#define   BGMAC_DMA_TX_ERR_CORE                        0x50000000
+#define BGMAC_DMA_RX_CTL                       0x20
+#define  BGMAC_DMA_RX_ENABLE                   0x00000001
+#define  BGMAC_DMA_RX_FRAME_OFFSET_MASK                0x000000FE
+#define  BGMAC_DMA_RX_FRAME_OFFSET_SHIFT       1
+#define  BGMAC_DMA_RX_DIRECT_FIFO              0x00000100
+#define  BGMAC_DMA_RX_OVERFLOW_CONT            0x00000400
+#define  BGMAC_DMA_RX_PARITY_DISABLE           0x00000800
+#define  BGMAC_DMA_RX_ADDREXT_MASK             0x00030000
+#define  BGMAC_DMA_RX_ADDREXT_SHIFT            16
+#define BGMAC_DMA_RX_INDEX                     0x24
+#define BGMAC_DMA_RX_RINGLO                    0x28
+#define BGMAC_DMA_RX_RINGHI                    0x2C
+#define BGMAC_DMA_RX_STATUS                    0x30
+#define  BGMAC_DMA_RX_STATDPTR                 0x00001FFF
+#define  BGMAC_DMA_RX_STAT                     0xF0000000
+#define   BGMAC_DMA_RX_STAT_DISABLED           0x00000000
+#define   BGMAC_DMA_RX_STAT_ACTIVE             0x10000000
+#define   BGMAC_DMA_RX_STAT_IDLEWAIT           0x20000000
+#define   BGMAC_DMA_RX_STAT_STOPPED            0x30000000
+#define   BGMAC_DMA_RX_STAT_SUSP               0x40000000
+#define BGMAC_DMA_RX_ERROR                     0x34
+#define  BGMAC_DMA_RX_ERRDPTR                  0x0001FFFF
+#define  BGMAC_DMA_RX_ERR                      0xF0000000
+#define   BGMAC_DMA_RX_ERR_NOERR               0x00000000
+#define   BGMAC_DMA_RX_ERR_PROT                        0x10000000
+#define   BGMAC_DMA_RX_ERR_UNDERRUN            0x20000000
+#define   BGMAC_DMA_RX_ERR_TRANSFER            0x30000000
+#define   BGMAC_DMA_RX_ERR_DESCREAD            0x40000000
+#define   BGMAC_DMA_RX_ERR_CORE                        0x50000000
+
+#define BGMAC_DESC_CTL0_EOT                    0x10000000      /* End of ring */
+#define BGMAC_DESC_CTL0_IOC                    0x20000000      /* IRQ on complete */
+#define BGMAC_DESC_CTL0_SOF                    0x40000000      /* Start of frame */
+#define BGMAC_DESC_CTL0_EOF                    0x80000000      /* End of frame */
+#define BGMAC_DESC_CTL1_LEN                    0x00001FFF
+
+#define BGMAC_PHY_NOREGS                       0x1E
+#define BGMAC_PHY_MASK                         0x1F
+
+#define BGMAC_MAX_TX_RINGS                     4
+#define BGMAC_MAX_RX_RINGS                     1
+
+#define BGMAC_TX_RING_SLOTS                    128
+#define BGMAC_RX_RING_SLOTS                    512 - 1         /* Why -1? Well, Broadcom does that... */
+
+#define BGMAC_RX_HEADER_LEN                    28              /* Last 24 bytes are unused. Well... */
+#define BGMAC_RX_FRAME_OFFSET                  30              /* There are 2 unused bytes between header and real data */
+#define BGMAC_RX_MAX_FRAME_SIZE                        1536            /* Copied from b44/tg3 */
+#define BGMAC_RX_BUF_SIZE                      (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
+
+#define BGMAC_BFL_ENETROBO                     0x0010          /* has ephy roboswitch spi */
+#define BGMAC_BFL_ENETADM                      0x0080          /* has ADMtek switch */
+#define BGMAC_BFL_ENETVLAN                     0x0100          /* can do vlan */
+
+#define BGMAC_CHIPCTL_1_IF_TYPE_MASK           0x00000030
+#define BGMAC_CHIPCTL_1_IF_TYPE_RMII           0x00000000
+#define BGMAC_CHIPCTL_1_IF_TYPE_MI             0x00000010
+#define BGMAC_CHIPCTL_1_IF_TYPE_RGMII          0x00000020
+#define BGMAC_CHIPCTL_1_SW_TYPE_MASK           0x000000C0
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHY           0x00000000
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHYMII                0x00000040
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII       0x00000080
+#define BGMAC_CHIPCTL_1_SW_TYPE_RGMI           0x000000C0
+#define BGMAC_CHIPCTL_1_RXC_DLL_BYPASS         0x00010000
+
+#define BGMAC_SPEED_10                         0x0001
+#define BGMAC_SPEED_100                                0x0002
+#define BGMAC_SPEED_1000                       0x0004
+
+#define BGMAC_WEIGHT   64
+
+#define ETHER_MAX_LEN   1518
+
+struct bgmac_slot_info {
+       struct sk_buff *skb;
+       dma_addr_t dma_addr;
+};
+
+struct bgmac_dma_desc {
+       __le32 ctl0;
+       __le32 ctl1;
+       __le32 addr_low;
+       __le32 addr_high;
+} __packed;
+
+enum bgmac_dma_ring_type {
+       BGMAC_DMA_RING_TX,
+       BGMAC_DMA_RING_RX,
+};
+
+/**
+ * bgmac_dma_ring - contains info about DMA ring (either TX or RX one)
+ * @start: index of the first slot containing data
+ * @end: index of a slot that can *not* be read (yet)
+ *
+ * Be really aware of the specific @end meaning. It's an index of a slot *after*
+ * the one containing data that can be read. If @start equals @end the ring is
+ * empty.
+ */
+struct bgmac_dma_ring {
+       u16 num_slots;
+       u16 start;
+       u16 end;
+
+       u16 mmio_base;
+       struct bgmac_dma_desc *cpu_base;
+       dma_addr_t dma_base;
+
+       struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS];
+};
+
+struct bgmac_rx_header {
+       __le16 len;
+       __le16 flags;
+       __le16 pad[12];
+};
+
+struct bgmac {
+       struct bcma_device *core;
+       struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
+       struct net_device *net_dev;
+       struct napi_struct napi;
+
+       /* DMA */
+       struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
+       struct bgmac_dma_ring rx_ring[BGMAC_MAX_RX_RINGS];
+
+       /* Stats */
+       bool stats_grabbed;
+       u32 mib_tx_regs[BGMAC_NUM_MIB_TX_REGS];
+       u32 mib_rx_regs[BGMAC_NUM_MIB_RX_REGS];
+
+       /* Int */
+       u32 int_mask;
+       u32 int_status;
+
+       /* Speed-related */
+       int speed;
+       bool autoneg;
+       bool full_duplex;
+
+       u8 phyaddr;
+       bool has_robosw;
+
+       bool loopback;
+};
+
+static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
+{
+       return bcma_read32(bgmac->core, offset);
+}
+
+static inline void bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
+{
+       bcma_write32(bgmac->core, offset, value);
+}
+
+static inline void bgmac_maskset(struct bgmac *bgmac, u16 offset, u32 mask,
+                                  u32 set)
+{
+       bgmac_write(bgmac, offset, (bgmac_read(bgmac, offset) & mask) | set);
+}
+
+static inline void bgmac_mask(struct bgmac *bgmac, u16 offset, u32 mask)
+{
+       bgmac_maskset(bgmac, offset, mask, 0);
+}
+
+static inline void bgmac_set(struct bgmac *bgmac, u16 offset, u32 set)
+{
+       bgmac_maskset(bgmac, offset, ~0, set);
+}
+
+u16 bgmac_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg);
+void bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value);
+
+#endif /* _BGMAC_H */
index a1adfaf87f499bc84a77dbc714abf8eba3adb4ef..2f0ba8f2fd6c08f85547c11eb9744c831caea23c 100644 (file)
@@ -8543,7 +8543,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_set_drvdata(pdev, dev);
 
        memcpy(dev->dev_addr, bp->mac_addr, 6);
-       memcpy(dev->perm_addr, bp->mac_addr, 6);
 
        dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
                NETIF_F_TSO | NETIF_F_TSO_ECN |
index 48fbdd48f88f9fcf5a9d3b35f60b250fa45cb329..116762daae09e3f15223b4482560d71d4ea1f62f 100644 (file)
@@ -4,4 +4,5 @@
 
 obj-$(CONFIG_BNX2X) += bnx2x.o
 
-bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
+bnx2x-y := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
+bnx2x-$(CONFIG_BNX2X_SRIOV) += bnx2x_vfpf.o bnx2x_sriov.o
index e8d4db10c8f318dacac488af5f41510c7f3c68dc..e4605a965084d18d65de70ab46c8ccbc7debe907 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #ifndef BNX2X_H
 #define BNX2X_H
+
+#include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/dma-mapping.h>
 #include <linux/types.h>
+#include <linux/pci_regs.h>
 
 /* compilation time flags */
 
@@ -23,8 +26,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.78.00-0"
-#define DRV_MODULE_RELDATE      "2012/09/27"
+#define DRV_MODULE_VERSION      "1.78.02-0"
+#define DRV_MODULE_RELDATE      "2013/01/14"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_DCB)
 #include "bnx2x_sp.h"
 #include "bnx2x_dcb.h"
 #include "bnx2x_stats.h"
+#include "bnx2x_vfpf.h"
+
+enum bnx2x_int_mode {
+       BNX2X_INT_MODE_MSIX,
+       BNX2X_INT_MODE_INTX,
+       BNX2X_INT_MODE_MSI
+};
 
 /* error/debug prints */
 
@@ -112,29 +122,29 @@ do {                                                               \
                dev_info(&bp->pdev->dev, fmt, ##__VA_ARGS__);    \
 } while (0)
 
+/* Error handling */
+void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int);
 #ifdef BNX2X_STOP_ON_ERROR
-void bnx2x_int_disable(struct bnx2x *bp);
 #define bnx2x_panic()                          \
 do {                                           \
        bp->panic = 1;                          \
        BNX2X_ERR("driver assert\n");           \
-       bnx2x_int_disable(bp);                  \
-       bnx2x_panic_dump(bp);                   \
+       bnx2x_panic_dump(bp, true);             \
 } while (0)
 #else
 #define bnx2x_panic()                          \
 do {                                           \
        bp->panic = 1;                          \
        BNX2X_ERR("driver assert\n");           \
-       bnx2x_panic_dump(bp);                   \
+       bnx2x_panic_dump(bp, false);            \
 } while (0)
 #endif
 
 #define bnx2x_mc_addr(ha)      ((ha)->addr)
 #define bnx2x_uc_addr(ha)      ((ha)->addr)
 
-#define U64_LO(x)                      (u32)(((u64)(x)) & 0xffffffff)
-#define U64_HI(x)                      (u32)(((u64)(x)) >> 32)
+#define U64_LO(x)                      ((u32)(((u64)(x)) & 0xffffffff))
+#define U64_HI(x)                      ((u32)(((u64)(x)) >> 32))
 #define HILO_U64(hi, lo)               ((((u64)(hi)) << 32) + (lo))
 
 
@@ -334,6 +344,9 @@ union db_prod {
 #define SGE_PAGE_SIZE          PAGE_SIZE
 #define SGE_PAGE_SHIFT         PAGE_SHIFT
 #define SGE_PAGE_ALIGN(addr)   PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
+#define SGE_PAGES              (SGE_PAGE_SIZE * PAGES_PER_SGE)
+#define TPA_AGG_SIZE           min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) * \
+                                           SGE_PAGES), 0xffff)
 
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES       2
@@ -789,48 +802,63 @@ struct bnx2x_common {
 #define CHIP_NUM_57711E                        0x1650
 #define CHIP_NUM_57712                 0x1662
 #define CHIP_NUM_57712_MF              0x1663
+#define CHIP_NUM_57712_VF              0x166f
 #define CHIP_NUM_57713                 0x1651
 #define CHIP_NUM_57713E                        0x1652
 #define CHIP_NUM_57800                 0x168a
 #define CHIP_NUM_57800_MF              0x16a5
+#define CHIP_NUM_57800_VF              0x16a9
 #define CHIP_NUM_57810                 0x168e
 #define CHIP_NUM_57810_MF              0x16ae
+#define CHIP_NUM_57810_VF              0x16af
 #define CHIP_NUM_57811                 0x163d
 #define CHIP_NUM_57811_MF              0x163e
-#define CHIP_NUM_57840_OBSOLETE        0x168d
+#define CHIP_NUM_57811_VF              0x163f
+#define CHIP_NUM_57840_OBSOLETE                0x168d
 #define CHIP_NUM_57840_MF_OBSOLETE     0x16ab
 #define CHIP_NUM_57840_4_10            0x16a1
 #define CHIP_NUM_57840_2_20            0x16a2
 #define CHIP_NUM_57840_MF              0x16a4
+#define CHIP_NUM_57840_VF              0x16ad
 #define CHIP_IS_E1(bp)                 (CHIP_NUM(bp) == CHIP_NUM_57710)
 #define CHIP_IS_57711(bp)              (CHIP_NUM(bp) == CHIP_NUM_57711)
 #define CHIP_IS_57711E(bp)             (CHIP_NUM(bp) == CHIP_NUM_57711E)
 #define CHIP_IS_57712(bp)              (CHIP_NUM(bp) == CHIP_NUM_57712)
+#define CHIP_IS_57712_VF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57712_VF)
 #define CHIP_IS_57712_MF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57712_MF)
 #define CHIP_IS_57800(bp)              (CHIP_NUM(bp) == CHIP_NUM_57800)
 #define CHIP_IS_57800_MF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57800_MF)
+#define CHIP_IS_57800_VF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57800_VF)
 #define CHIP_IS_57810(bp)              (CHIP_NUM(bp) == CHIP_NUM_57810)
 #define CHIP_IS_57810_MF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57810_MF)
+#define CHIP_IS_57810_VF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57810_VF)
 #define CHIP_IS_57811(bp)              (CHIP_NUM(bp) == CHIP_NUM_57811)
 #define CHIP_IS_57811_MF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57811_MF)
+#define CHIP_IS_57811_VF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57811_VF)
 #define CHIP_IS_57840(bp)              \
                ((CHIP_NUM(bp) == CHIP_NUM_57840_4_10) || \
                 (CHIP_NUM(bp) == CHIP_NUM_57840_2_20) || \
                 (CHIP_NUM(bp) == CHIP_NUM_57840_OBSOLETE))
 #define CHIP_IS_57840_MF(bp)   ((CHIP_NUM(bp) == CHIP_NUM_57840_MF) || \
                                 (CHIP_NUM(bp) == CHIP_NUM_57840_MF_OBSOLETE))
+#define CHIP_IS_57840_VF(bp)           (CHIP_NUM(bp) == CHIP_NUM_57840_VF)
 #define CHIP_IS_E1H(bp)                        (CHIP_IS_57711(bp) || \
                                         CHIP_IS_57711E(bp))
 #define CHIP_IS_E2(bp)                 (CHIP_IS_57712(bp) || \
-                                        CHIP_IS_57712_MF(bp))
+                                        CHIP_IS_57712_MF(bp) || \
+                                        CHIP_IS_57712_VF(bp))
 #define CHIP_IS_E3(bp)                 (CHIP_IS_57800(bp) || \
                                         CHIP_IS_57800_MF(bp) || \
+                                        CHIP_IS_57800_VF(bp) || \
                                         CHIP_IS_57810(bp) || \
                                         CHIP_IS_57810_MF(bp) || \
+                                        CHIP_IS_57810_VF(bp) || \
                                         CHIP_IS_57811(bp) || \
                                         CHIP_IS_57811_MF(bp) || \
+                                        CHIP_IS_57811_VF(bp) || \
                                         CHIP_IS_57840(bp) || \
-                                        CHIP_IS_57840_MF(bp))
+                                        CHIP_IS_57840_MF(bp) || \
+                                        CHIP_IS_57840_VF(bp))
 #define CHIP_IS_E1x(bp)                        (CHIP_IS_E1((bp)) || CHIP_IS_E1H((bp)))
 #define USES_WARPCORE(bp)              (CHIP_IS_E3(bp))
 #define IS_E1H_OFFSET                  (!CHIP_IS_E1(bp))
@@ -954,6 +982,11 @@ struct bnx2x_port {
 extern struct workqueue_struct *bnx2x_wq;
 
 #define BNX2X_MAX_NUM_OF_VFS   64
+#define BNX2X_VF_CID_WND       0
+#define BNX2X_CIDS_PER_VF      (1 << BNX2X_VF_CID_WND)
+#define BNX2X_CLIENTS_PER_VF   1
+#define BNX2X_FIRST_VF_CID     256
+#define BNX2X_VF_CIDS          (BNX2X_MAX_NUM_OF_VFS * BNX2X_CIDS_PER_VF)
 #define BNX2X_VF_ID_INVALID    0xFF
 
 /*
@@ -1104,6 +1137,7 @@ struct hw_context {
 /* forward */
 struct bnx2x_ilt;
 
+struct bnx2x_vfdb;
 
 enum bnx2x_recovery_state {
        BNX2X_RECOVERY_DONE,
@@ -1165,19 +1199,22 @@ struct bnx2x_fw_stats_req {
 };
 
 struct bnx2x_fw_stats_data {
-       struct stats_counter    storm_counters;
-       struct per_port_stats   port;
-       struct per_pf_stats     pf;
+       struct stats_counter            storm_counters;
+       struct per_port_stats           port;
+       struct per_pf_stats             pf;
        struct fcoe_statistics_params   fcoe;
-       struct per_queue_stats  queue_stats[1];
+       struct per_queue_stats          queue_stats[1];
 };
 
 /* Public slow path states */
 enum {
        BNX2X_SP_RTNL_SETUP_TC,
        BNX2X_SP_RTNL_TX_TIMEOUT,
-       BNX2X_SP_RTNL_AFEX_F_UPDATE,
        BNX2X_SP_RTNL_FAN_FAILURE,
+       BNX2X_SP_RTNL_AFEX_F_UPDATE,
+       BNX2X_SP_RTNL_ENABLE_SRIOV,
+       BNX2X_SP_RTNL_VFPF_MCAST,
+       BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
 };
 
 
@@ -1231,6 +1268,21 @@ struct bnx2x {
          (vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2  : 1))
 #define BP_FW_MB_IDX(bp)               BP_FW_MB_IDX_VN(bp, BP_VN(bp))
 
+#ifdef CONFIG_BNX2X_SRIOV
+       /* vf pf channel mailbox contains request and response buffers */
+       struct bnx2x_vf_mbx_msg *vf2pf_mbox;
+       dma_addr_t              vf2pf_mbox_mapping;
+
+       /* we set aside a copy of the acquire response */
+       struct pfvf_acquire_resp_tlv acquire_resp;
+
+       /* bulletin board for messages from pf to vf */
+       union pf_vf_bulletin   *pf2vf_bulletin;
+       dma_addr_t              pf2vf_bulletin_mapping;
+
+       struct pf_vf_bulletin_content   old_bulletin;
+#endif /* CONFIG_BNX2X_SRIOV */
+
        struct net_device       *dev;
        struct pci_dev          *pdev;
 
@@ -1295,8 +1347,6 @@ struct bnx2x {
        __le16                  *eq_cons_sb;
        atomic_t                eq_spq_left; /* COMMON_XXX ramrods credit */
 
-
-
        /* Counter for marking that there is a STAT_QUERY ramrod pending */
        u16                     stats_pending;
        /*  Counter for completed statistics ramrods */
@@ -1318,8 +1368,6 @@ struct bnx2x {
 #define DISABLE_MSI_FLAG               (1 << 7)
 #define TPA_ENABLE_FLAG                        (1 << 8)
 #define NO_MCP_FLAG                    (1 << 9)
-
-#define BP_NOMCP(bp)                   (bp->flags & NO_MCP_FLAG)
 #define GRO_ENABLE_FLAG                        (1 << 10)
 #define MF_FUNC_DIS                    (1 << 11)
 #define OWN_CNIC_IRQ                   (1 << 12)
@@ -1330,6 +1378,17 @@ struct bnx2x {
 #define BC_SUPPORTS_FCOE_FEATURES      (1 << 19)
 #define USING_SINGLE_MSIX_FLAG         (1 << 20)
 #define BC_SUPPORTS_DCBX_MSG_NON_PMF   (1 << 21)
+#define IS_VF_FLAG                     (1 << 22)
+
+#define BP_NOMCP(bp)                   ((bp)->flags & NO_MCP_FLAG)
+
+#ifdef CONFIG_BNX2X_SRIOV
+#define IS_VF(bp)                      ((bp)->flags & IS_VF_FLAG)
+#define IS_PF(bp)                      (!((bp)->flags & IS_VF_FLAG))
+#else
+#define IS_VF(bp)                      false
+#define IS_PF(bp)                      true
+#endif
 
 #define NO_ISCSI(bp)           ((bp)->flags & NO_ISCSI_FLAG)
 #define NO_ISCSI_OOO(bp)       ((bp)->flags & NO_ISCSI_OOO_FLAG)
@@ -1349,6 +1408,7 @@ struct bnx2x {
        int                     mrrs;
 
        struct delayed_work     sp_task;
+       atomic_t                interrupt_occurred;
        struct delayed_work     sp_rtnl_task;
 
        struct delayed_work     period_task;
@@ -1432,6 +1492,7 @@ struct bnx2x {
        u8                      igu_sb_cnt;
        u8                      min_msix_vec_cnt;
 
+       u32                     igu_base_addr;
        dma_addr_t              def_status_blk_mapping;
 
        struct bnx2x_slowpath   *slowpath;
@@ -1580,6 +1641,9 @@ struct bnx2x {
        char                    fw_ver[32];
        const struct firmware   *firmware;
 
+       struct bnx2x_vfdb       *vfdb;
+#define IS_SRIOV(bp)           ((bp)->vfdb)
+
        /* DCB support on/off */
        u16 dcb_state;
 #define BNX2X_DCB_STATE_OFF                    0
@@ -1599,6 +1663,10 @@ struct bnx2x {
        int                                     dcb_version;
 
        /* CAM credit pools */
+
+       /* used only in sriov */
+       struct bnx2x_credit_pool_obj            vlans_pool;
+
        struct bnx2x_credit_pool_obj            macs_pool;
 
        /* RX_MODE object */
@@ -1636,6 +1704,9 @@ struct bnx2x {
 
        /* priority to cos mapping */
        u8                                      prio_to_cos[8];
+
+       int fp_array_size;
+       u32 dump_preset_idx;
 };
 
 /* Tx queues may be less or equal to Rx queues */
@@ -1813,12 +1884,16 @@ int bnx2x_del_all_macs(struct bnx2x *bp,
 
 /* Init Function API  */
 void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p);
+void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
+                   u8 vf_valid, int fw_sb_id, int igu_sb_id);
+u32 bnx2x_get_pretend_reg(struct bnx2x *bp);
 int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
 int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode);
 int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 void bnx2x_read_mf_cfg(struct bnx2x *bp);
 
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val);
 
 /* dmae */
 void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
@@ -1830,6 +1905,18 @@ u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode);
 u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
                      bool with_comp, u8 comp_type);
 
+void bnx2x_prep_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
+                              u8 src_type, u8 dst_type);
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae);
+void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl);
+
+/* FLR related routines */
+u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp);
+void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count);
+int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt);
+u8 bnx2x_is_pcie_pending(struct pci_dev *dev);
+int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
+                                   char *msg, u32 poll_cnt);
 
 void bnx2x_calc_fc_adv(struct bnx2x *bp);
 int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
@@ -1854,6 +1941,9 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
        return val;
 }
 
+void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
+                           bool is_pf);
+
 #define BNX2X_ILT_ZALLOC(x, y, size) \
        do { \
                x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
@@ -1990,10 +2080,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define BNX2X_LOOPBACK_FAILED          (BNX2X_MAC_LOOPBACK_FAILED | \
                                         BNX2X_PHY_LOOPBACK_FAILED)
 
-
 #define STROM_ASSERT_ARRAY_SIZE                50
 
-
 /* must be used on a CID before placing it on a HW ring */
 #define HW_CID(bp, x)                  ((BP_PORT(bp) << 23) | \
                                         (BP_VN(bp) << BNX2X_SWCID_SHIFT) | \
@@ -2024,7 +2112,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 /* Memory of fairness algorithm . 2 cycles */
 #define FAIR_MEM                                       2
 
-
 #define ATTN_NIG_FOR_FUNC              (1L << 8)
 #define ATTN_SW_TIMER_4_FUNC           (1L << 9)
 #define GPIO_2_FUNC                    (1L << 10)
@@ -2067,6 +2154,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
                                (AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \
                                 AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \
                                 AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \
+                                AEU_INPUTS_ATTN_BITS_BRB_HW_INTERRUPT | \
                                 AEU_INPUTS_ATTN_BITS_PBCLIENT_HW_INTERRUPT)
 #define HW_PRTY_ASSERT_SET_0   (AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \
                                 AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR | \
@@ -2128,7 +2216,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 
 #define MULTI_MASK                     0x7f
 
-
 #define DEF_USB_FUNC_OFF       offsetof(struct cstorm_def_status_block_u, func)
 #define DEF_CSB_FUNC_OFF       offsetof(struct cstorm_def_status_block_c, func)
 #define DEF_XSB_FUNC_OFF       offsetof(struct xstorm_def_status_block, func)
@@ -2156,18 +2243,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
                (&bp->def_status_blk->sp_sb.\
                                        index_values[HC_SP_INDEX_ETH_DEF_CONS])
 
-#define SET_FLAG(value, mask, flag) \
-       do {\
-               (value) &= ~(mask);\
-               (value) |= ((flag) << (mask##_SHIFT));\
-       } while (0)
-
-#define GET_FLAG(value, mask) \
-       (((value) & (mask)) >> (mask##_SHIFT))
-
-#define GET_FIELD(value, fname) \
-       (((value) & (fname##_MASK)) >> (fname##_SHIFT))
-
 #define CAM_IS_INVALID(x) \
        (GET_FLAG(x.flags, \
        MAC_CONFIGURATION_ENTRY_ACTION_TYPE) == \
@@ -2178,7 +2253,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define MC_HASH_OFFSET(bp, i)          (BAR_TSTRORM_INTMEM + \
        TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(BP_FUNC(bp)) + i*4)
 
-
 #ifndef PXP2_REG_PXP2_INT_STS
 #define PXP2_REG_PXP2_INT_STS          PXP2_REG_PXP2_INT_STS_0
 #endif
@@ -2190,9 +2264,16 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define BNX2X_VPD_LEN                  128
 #define VENDOR_ID_LEN                  4
 
+#define VF_ACQUIRE_THRESH              3
+#define VF_ACQUIRE_MAC_FILTERS         1
+#define VF_ACQUIRE_MC_FILTERS          10
+
+#define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \
+                           (!((me_reg) & ME_REG_VF_ERR)))
+int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code);
 /* Congestion management fairness mode */
-#define CMNG_FNS_NONE          0
-#define CMNG_FNS_MINMAX                1
+#define CMNG_FNS_NONE                  0
+#define CMNG_FNS_MINMAX                        1
 
 #define HC_SEG_ACCESS_DEF              0   /*Driver decision 0-3*/
 #define HC_SEG_ACCESS_ATTN             4
@@ -2208,7 +2289,6 @@ static const u32 dmae_reg_go_c[] = {
 void bnx2x_set_ethtool_ops(struct net_device *netdev);
 void bnx2x_notify_link_changed(struct bnx2x *bp);
 
-
 #define BNX2X_MF_SD_PROTOCOL(bp) \
        ((bp)->mf_config[BP_VN(bp)] & FUNC_MF_CFG_PROTOCOL_MASK)
 
@@ -2229,6 +2309,18 @@ void bnx2x_notify_link_changed(struct bnx2x *bp);
                                (BNX2X_IS_MF_SD_PROTOCOL_ISCSI(bp) || \
                                 BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)))
 
+#define SET_FLAG(value, mask, flag) \
+       do {\
+               (value) &= ~(mask);\
+               (value) |= ((flag) << (mask##_SHIFT));\
+       } while (0)
+
+#define GET_FLAG(value, mask) \
+       (((value) & (mask)) >> (mask##_SHIFT))
+
+#define GET_FIELD(value, fname) \
+       (((value) & (fname##_MASK)) >> (fname##_SHIFT))
+
 enum {
        SWITCH_UPDATE,
        AFEX_UPDATE,
index f771ddfba646b0a773e89f3365b8add151087836..ecac04a3687c6b2967ccc3e8e1ab78bf2107e4e9 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_cmn.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
 #include <linux/if_vlan.h>
 #include <linux/interrupt.h>
 #include <linux/ip.h>
+#include <net/tcp.h>
 #include <net/ipv6.h>
 #include <net/ip6_checksum.h>
 #include <linux/prefetch.h>
@@ -28,8 +29,6 @@
 #include "bnx2x_init.h"
 #include "bnx2x_sp.h"
 
-
-
 /**
  * bnx2x_move_fp - move content of the fastpath structure.
  *
@@ -86,6 +85,34 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
        to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index];
 }
 
+/**
+ * bnx2x_fill_fw_str - Fill buffer with FW version string.
+ *
+ * @bp:        driver handle
+ * @buf:       character buffer to fill with the fw name
+ * @buf_len:   length of the above buffer
+ *
+ */
+void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len)
+{
+       if (IS_PF(bp)) {
+               u8 phy_fw_ver[PHY_FW_VER_LEN];
+
+               phy_fw_ver[0] = '\0';
+               bnx2x_get_ext_phy_fw_version(&bp->link_params,
+                                            phy_fw_ver, PHY_FW_VER_LEN);
+               strlcpy(buf, bp->fw_ver, buf_len);
+               snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+                        "bc %d.%d.%d%s%s",
+                        (bp->common.bc_ver & 0xff0000) >> 16,
+                        (bp->common.bc_ver & 0xff00) >> 8,
+                        (bp->common.bc_ver & 0xff),
+                        ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+       } else {
+               bnx2x_vf_fill_fw_str(bp, buf, buf_len);
+       }
+}
+
 /**
  * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact
  *
@@ -210,7 +237,7 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata)
                   txdata->txq_index, hw_cons, sw_cons, pkt_cons);
 
                bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons,
-                   &pkts_compl, &bytes_compl);
+                                           &pkts_compl, &bytes_compl);
 
                sw_cons++;
        }
@@ -316,14 +343,14 @@ static inline void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
           fp->last_max_sge, fp->rx_sge_prod);
 }
 
-/* Set Toeplitz hash value in the skb using the value from the
+/* Get Toeplitz hash value in the skb using the value from the
  * CQE (calculated by HW).
  */
 static u32 bnx2x_get_rxhash(const struct bnx2x *bp,
                            const struct eth_fast_path_rx_cqe *cqe,
                            bool *l4_rxhash)
 {
-       /* Set Toeplitz hash from CQE */
+       /* Get Toeplitz hash from CQE */
        if ((bp->dev->features & NETIF_F_RXHASH) &&
            (cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG)) {
                enum eth_rss_hash_type htype;
@@ -390,8 +417,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
        tpa_info->rxhash = bnx2x_get_rxhash(bp, cqe, &tpa_info->l4_rxhash);
        if (fp->mode == TPA_MODE_GRO) {
                u16 gro_size = le16_to_cpu(cqe->pkt_len_or_gro_seg_len);
-               tpa_info->full_page =
-                       SGE_PAGE_SIZE * PAGES_PER_SGE / gro_size * gro_size;
+               tpa_info->full_page = SGE_PAGES / gro_size * gro_size;
                tpa_info->gro_size = gro_size;
        }
 
@@ -412,31 +438,34 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
  */
 #define TPA_TSTAMP_OPT_LEN     12
 /**
- * bnx2x_set_lro_mss - calculate the approximate value of the MSS
+ * bnx2x_set_gro_params - compute GRO values
  *
- * @bp:                        driver handle
+ * @skb:               packet skb
  * @parsing_flags:     parsing flags from the START CQE
  * @len_on_bd:         total length of the first packet for the
  *                     aggregation.
+ * @pkt_len:           length of all segments
  *
  * Approximate value of the MSS for this aggregation calculated using
  * the first packet of it.
+ * Compute number of aggregated segments, and gso_type.
  */
-static u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
-                            u16 len_on_bd)
+static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
+                                u16 len_on_bd, unsigned int pkt_len)
 {
-       /*
-        * TPA arrgregation won't have either IP options or TCP options
+       /* TPA aggregation won't have either IP options or TCP options
         * other than timestamp or IPv6 extension headers.
         */
        u16 hdrs_len = ETH_HLEN + sizeof(struct tcphdr);
 
        if (GET_FLAG(parsing_flags, PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
-           PRS_FLAG_OVERETH_IPV6)
+           PRS_FLAG_OVERETH_IPV6) {
                hdrs_len += sizeof(struct ipv6hdr);
-       else /* IPv4 */
+               skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+       } else {
                hdrs_len += sizeof(struct iphdr);
-
+               skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+       }
 
        /* Check if there was a TCP timestamp, if there is it's will
         * always be 12 bytes length: nop nop kind length echo val.
@@ -446,7 +475,13 @@ static u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
        if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG)
                hdrs_len += TPA_TSTAMP_OPT_LEN;
 
-       return len_on_bd - hdrs_len;
+       skb_shinfo(skb)->gso_size = len_on_bd - hdrs_len;
+
+       /* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count
+        * to skb_shinfo(skb)->gso_segs
+        */
+       NAPI_GRO_CB(skb)->count = DIV_ROUND_UP(pkt_len - hdrs_len,
+                                              skb_shinfo(skb)->gso_size);
 }
 
 static int bnx2x_alloc_rx_sge(struct bnx2x *bp,
@@ -463,7 +498,7 @@ static int bnx2x_alloc_rx_sge(struct bnx2x *bp,
        }
 
        mapping = dma_map_page(&bp->pdev->dev, page, 0,
-                              SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+                              SGE_PAGES, DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                __free_pages(page, PAGES_PER_SGE_SHIFT);
                BNX2X_ERR("Can't map sge\n");
@@ -500,22 +535,12 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        }
 
        /* This is needed in order to enable forwarding support */
-       if (frag_size) {
-               skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp,
-                                       tpa_info->parsing_flags, len_on_bd);
-
-               /* set for GRO */
-               if (fp->mode == TPA_MODE_GRO)
-                       skb_shinfo(skb)->gso_type =
-                           (GET_FLAG(tpa_info->parsing_flags,
-                                     PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
-                                               PRS_FLAG_OVERETH_IPV6) ?
-                               SKB_GSO_TCPV6 : SKB_GSO_TCPV4;
-       }
-
+       if (frag_size)
+               bnx2x_set_gro_params(skb, tpa_info->parsing_flags, len_on_bd,
+                                    le16_to_cpu(cqe->pkt_len));
 
 #ifdef BNX2X_STOP_ON_ERROR
-       if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
+       if (pages > min_t(u32, 8, MAX_SKB_FRAGS) * SGE_PAGES) {
                BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
                          pages, cqe_idx);
                BNX2X_ERR("cqe->pkt_len = %d\n", cqe->pkt_len);
@@ -533,8 +558,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                if (fp->mode == TPA_MODE_GRO)
                        frag_len = min_t(u32, frag_size, (u32)full_page);
                else /* LRO */
-                       frag_len = min_t(u32, frag_size,
-                                        (u32)(SGE_PAGE_SIZE * PAGES_PER_SGE));
+                       frag_len = min_t(u32, frag_size, (u32)SGE_PAGES);
 
                rx_pg = &fp->rx_page_ring[sge_idx];
                old_rx_pg = *rx_pg;
@@ -550,7 +574,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                /* Unmap the page as we r going to pass it to the stack */
                dma_unmap_page(&bp->pdev->dev,
                               dma_unmap_addr(&old_rx_pg, mapping),
-                              SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+                              SGE_PAGES, DMA_FROM_DEVICE);
                /* Add one frag and update the appropriate fields in the skb */
                if (fp->mode == TPA_MODE_LRO)
                        skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
@@ -568,7 +592,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 
                skb->data_len += frag_len;
-               skb->truesize += SGE_PAGE_SIZE * PAGES_PER_SGE;
+               skb->truesize += SGE_PAGES;
                skb->len += frag_len;
 
                frag_size -= frag_len;
@@ -593,6 +617,54 @@ static void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp)
        return kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
 }
 
+#ifdef CONFIG_INET
+static void bnx2x_gro_ip_csum(struct bnx2x *bp, struct sk_buff *skb)
+{
+       const struct iphdr *iph = ip_hdr(skb);
+       struct tcphdr *th;
+
+       skb_set_transport_header(skb, sizeof(struct iphdr));
+       th = tcp_hdr(skb);
+
+       th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
+                                 iph->saddr, iph->daddr, 0);
+}
+
+static void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb)
+{
+       struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct tcphdr *th;
+
+       skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+       th = tcp_hdr(skb);
+
+       th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
+                                 &iph->saddr, &iph->daddr, 0);
+}
+#endif
+
+static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+                              struct sk_buff *skb)
+{
+#ifdef CONFIG_INET
+       if (skb_shinfo(skb)->gso_size) {
+               skb_set_network_header(skb, 0);
+               switch (be16_to_cpu(skb->protocol)) {
+               case ETH_P_IP:
+                       bnx2x_gro_ip_csum(bp, skb);
+                       break;
+               case ETH_P_IPV6:
+                       bnx2x_gro_ipv6_csum(bp, skb);
+                       break;
+               default:
+                       BNX2X_ERR("FW GRO supports only IPv4/IPv6, not 0x%04x\n",
+                                 be16_to_cpu(skb->protocol));
+               }
+               tcp_gro_complete(skb);
+       }
+#endif
+       napi_gro_receive(&fp->napi, skb);
+}
 
 static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                           struct bnx2x_agg_info *tpa_info,
@@ -647,7 +719,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                                         skb, cqe, cqe_idx)) {
                        if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN)
                                __vlan_hwaccel_put_tag(skb, tpa_info->vlan_tag);
-                       napi_gro_receive(&fp->napi, skb);
+                       bnx2x_gro_receive(bp, fp, skb);
                } else {
                        DP(NETIF_MSG_RX_STATUS,
                           "Failed to allocate new pages - dropping packet!\n");
@@ -1089,7 +1161,7 @@ void __bnx2x_link_report(struct bnx2x *bp)
        struct bnx2x_link_report_data cur_data;
 
        /* reread mf_cfg */
-       if (!CHIP_IS_E1(bp))
+       if (IS_PF(bp) && !CHIP_IS_E1(bp))
                bnx2x_read_mf_cfg(bp);
 
        /* Read the current link report info */
@@ -1431,10 +1503,14 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
 
        if (nvecs == offset)
                return;
-       free_irq(bp->msix_table[offset].vector, bp->dev);
-       DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
-          bp->msix_table[offset].vector);
-       offset++;
+
+       /* VFs don't have a default SB */
+       if (IS_PF(bp)) {
+               free_irq(bp->msix_table[offset].vector, bp->dev);
+               DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
+                  bp->msix_table[offset].vector);
+               offset++;
+       }
 
        if (CNIC_SUPPORT(bp)) {
                if (nvecs == offset)
@@ -1455,21 +1531,30 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
 void bnx2x_free_irq(struct bnx2x *bp)
 {
        if (bp->flags & USING_MSIX_FLAG &&
-           !(bp->flags & USING_SINGLE_MSIX_FLAG))
-               bnx2x_free_msix_irqs(bp, BNX2X_NUM_ETH_QUEUES(bp) +
-                                    CNIC_SUPPORT(bp) + 1);
-       else
+           !(bp->flags & USING_SINGLE_MSIX_FLAG)) {
+               int nvecs = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp);
+
+               /* vfs don't have a default status block */
+               if (IS_PF(bp))
+                       nvecs++;
+
+               bnx2x_free_msix_irqs(bp, nvecs);
+       } else {
                free_irq(bp->dev->irq, bp->dev);
+       }
 }
 
 int bnx2x_enable_msix(struct bnx2x *bp)
 {
-       int msix_vec = 0, i, rc, req_cnt;
+       int msix_vec = 0, i, rc;
 
-       bp->msix_table[msix_vec].entry = msix_vec;
-       BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
-          bp->msix_table[0].entry);
-       msix_vec++;
+       /* VFs don't have a default status block */
+       if (IS_PF(bp)) {
+               bp->msix_table[msix_vec].entry = msix_vec;
+               BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
+                              bp->msix_table[0].entry);
+               msix_vec++;
+       }
 
        /* Cnic requires an msix vector for itself */
        if (CNIC_SUPPORT(bp)) {
@@ -1487,9 +1572,10 @@ int bnx2x_enable_msix(struct bnx2x *bp)
                msix_vec++;
        }
 
-       req_cnt = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp) + 1;
+       DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n",
+          msix_vec);
 
-       rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt);
+       rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], msix_vec);
 
        /*
         * reconfigure number of tx/rx queues according to available
@@ -1497,7 +1583,7 @@ int bnx2x_enable_msix(struct bnx2x *bp)
         */
        if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) {
                /* how less vectors we will have? */
-               int diff = req_cnt - rc;
+               int diff = msix_vec - rc;
 
                BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
 
@@ -1551,12 +1637,15 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
 {
        int i, rc, offset = 0;
 
-       rc = request_irq(bp->msix_table[offset++].vector,
-                        bnx2x_msix_sp_int, 0,
-                        bp->dev->name, bp->dev);
-       if (rc) {
-               BNX2X_ERR("request sp irq failed\n");
-               return -EBUSY;
+       /* no default status block for vf */
+       if (IS_PF(bp)) {
+               rc = request_irq(bp->msix_table[offset++].vector,
+                                bnx2x_msix_sp_int, 0,
+                                bp->dev->name, bp->dev);
+               if (rc) {
+                       BNX2X_ERR("request sp irq failed\n");
+                       return -EBUSY;
+               }
        }
 
        if (CNIC_SUPPORT(bp))
@@ -1580,12 +1669,20 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
        }
 
        i = BNX2X_NUM_ETH_QUEUES(bp);
-       offset = 1 + CNIC_SUPPORT(bp);
-       netdev_info(bp->dev, "using MSI-X  IRQs: sp %d  fp[%d] %d ... fp[%d] %d\n",
-              bp->msix_table[0].vector,
-              0, bp->msix_table[offset].vector,
-              i - 1, bp->msix_table[offset + i - 1].vector);
-
+       if (IS_PF(bp)) {
+               offset = 1 + CNIC_SUPPORT(bp);
+               netdev_info(bp->dev,
+                           "using MSI-X  IRQs: sp %d  fp[%d] %d ... fp[%d] %d\n",
+                           bp->msix_table[0].vector,
+                           0, bp->msix_table[offset].vector,
+                           i - 1, bp->msix_table[offset + i - 1].vector);
+       } else {
+               offset = CNIC_SUPPORT(bp);
+               netdev_info(bp->dev,
+                           "using MSI-X  IRQs: fp[%d] %d ... fp[%d] %d\n",
+                           0, bp->msix_table[offset].vector,
+                           i - 1, bp->msix_table[offset + i - 1].vector);
+       }
        return 0;
 }
 
@@ -1630,7 +1727,6 @@ static int bnx2x_setup_irqs(struct bnx2x *bp)
                if (rc)
                        return rc;
        } else {
-               bnx2x_ack_int(bp);
                rc = bnx2x_req_irq(bp);
                if (rc) {
                        BNX2X_ERR("IRQ request failed  rc %d, aborting\n", rc);
@@ -1728,7 +1824,6 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
        return __skb_tx_hash(dev, skb, BNX2X_NUM_ETH_QUEUES(bp));
 }
 
-
 void bnx2x_set_num_queues(struct bnx2x *bp)
 {
        /* RSS queues */
@@ -1993,27 +2088,212 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp)
        } while (0)
 #endif /*BNX2X_STOP_ON_ERROR*/
 
-bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
+static void bnx2x_free_fw_stats_mem(struct bnx2x *bp)
+{
+       BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
+                      bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+       return;
+}
+
+static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
 {
-       /* build FW version dword */
-       u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
-                   (BCM_5710_FW_MINOR_VERSION << 8) +
-                   (BCM_5710_FW_REVISION_VERSION << 16) +
-                   (BCM_5710_FW_ENGINEERING_VERSION << 24);
+       int num_groups, vf_headroom = 0;
+       int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
+
+       /* number of queues for statistics is number of eth queues + FCoE */
+       u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
+
+       /* Total number of FW statistics requests =
+        * 1 for port stats + 1 for PF stats + potential 2 for FCoE (fcoe proper
+        * and fcoe l2 queue) stats + num of queues (which includes another 1
+        * for fcoe l2 queue if applicable)
+        */
+       bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
 
-       /* read loaded FW from chip */
-       u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
+       /* vf stats appear in the request list, but their data is allocated by
+        * the VFs themselves. We don't include them in the bp->fw_stats_num as
+        * it is used to determine where to place the vf stats queries in the
+        * request struct
+        */
+       if (IS_SRIOV(bp))
+               vf_headroom = bnx2x_vf_headroom(bp);
+
+       /* Request is built from stats_query_header and an array of
+        * stats_query_cmd_group each of which contains
+        * STATS_QUERY_CMD_COUNT rules. The real number or requests is
+        * configured in the stats_query_header.
+        */
+       num_groups =
+               (((bp->fw_stats_num + vf_headroom) / STATS_QUERY_CMD_COUNT) +
+                (((bp->fw_stats_num + vf_headroom) % STATS_QUERY_CMD_COUNT) ?
+                1 : 0));
+
+       DP(BNX2X_MSG_SP, "stats fw_stats_num %d, vf headroom %d, num_groups %d\n",
+          bp->fw_stats_num, vf_headroom, num_groups);
+       bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
+               num_groups * sizeof(struct stats_query_cmd_group);
+
+       /* Data for statistics requests + stats_counter
+        * stats_counter holds per-STORM counters that are incremented
+        * when STORM has finished with the current request.
+        * memory for FCoE offloaded statistics are counted anyway,
+        * even if they will not be sent.
+        * VF stats are not accounted for here as the data of VF stats is stored
+        * in memory allocated by the VF, not here.
+        */
+       bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
+               sizeof(struct per_pf_stats) +
+               sizeof(struct fcoe_statistics_params) +
+               sizeof(struct per_queue_stats) * num_queue_stats +
+               sizeof(struct stats_counter);
+
+       BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
+                       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+
+       /* Set shortcuts */
+       bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
+       bp->fw_stats_req_mapping = bp->fw_stats_mapping;
+       bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
+               ((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
+       bp->fw_stats_data_mapping = bp->fw_stats_mapping +
+               bp->fw_stats_req_sz;
+
+       DP(BNX2X_MSG_SP, "statistics request base address set to %x %x",
+          U64_HI(bp->fw_stats_req_mapping),
+          U64_LO(bp->fw_stats_req_mapping));
+       DP(BNX2X_MSG_SP, "statistics data base address set to %x %x",
+          U64_HI(bp->fw_stats_data_mapping),
+          U64_LO(bp->fw_stats_data_mapping));
+       return 0;
+
+alloc_mem_err:
+       bnx2x_free_fw_stats_mem(bp);
+       BNX2X_ERR("Can't allocate FW stats memory\n");
+       return -ENOMEM;
+}
 
-       DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw);
+/* send load request to mcp and analyze response */
+static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
+{
+       /* init fw_seq */
+       bp->fw_seq =
+               (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+                DRV_MSG_SEQ_NUMBER_MASK);
+       BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+
+       /* Get current FW pulse sequence */
+       bp->fw_drv_pulse_wr_seq =
+               (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
+                DRV_PULSE_SEQ_MASK);
+       BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
+
+       /* load request */
+       (*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
+                                       DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
+
+       /* if mcp fails to respond we must abort */
+       if (!(*load_code)) {
+               BNX2X_ERR("MCP response failure, aborting\n");
+               return -EBUSY;
+       }
+
+       /* If mcp refused (e.g. other port is in diagnostic mode) we
+        * must abort
+        */
+       if ((*load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+               BNX2X_ERR("MCP refused load request, aborting\n");
+               return -EBUSY;
+       }
+       return 0;
+}
 
-       if (loaded_fw != my_fw) {
-               if (is_err)
-                       BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n",
+/* check whether another PF has already loaded FW to chip. In
+ * virtualized environments a pf from another VM may have already
+ * initialized the device including loading FW
+ */
+int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code)
+{
+       /* is another pf loaded on this engine? */
+       if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
+           load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
+               /* build my FW version dword */
+               u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
+                       (BCM_5710_FW_MINOR_VERSION << 8) +
+                       (BCM_5710_FW_REVISION_VERSION << 16) +
+                       (BCM_5710_FW_ENGINEERING_VERSION << 24);
+
+               /* read loaded FW from chip */
+               u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
+
+               DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n",
+                  loaded_fw, my_fw);
+
+               /* abort nic load if version mismatch */
+               if (my_fw != loaded_fw) {
+                       BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. aborting\n",
                                  loaded_fw, my_fw);
-               return false;
+                       return -EBUSY;
+               }
+       }
+       return 0;
+}
+
+/* returns the "mcp load_code" according to global load_count array */
+static int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port)
+{
+       int path = BP_PATH(bp);
+
+       DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d]      %d, %d, %d\n",
+          path, load_count[path][0], load_count[path][1],
+          load_count[path][2]);
+       load_count[path][0]++;
+       load_count[path][1 + port]++;
+       DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d]  %d, %d, %d\n",
+          path, load_count[path][0], load_count[path][1],
+          load_count[path][2]);
+       if (load_count[path][0] == 1)
+               return FW_MSG_CODE_DRV_LOAD_COMMON;
+       else if (load_count[path][1 + port] == 1)
+               return FW_MSG_CODE_DRV_LOAD_PORT;
+       else
+               return FW_MSG_CODE_DRV_LOAD_FUNCTION;
+}
+
+/* mark PMF if applicable */
+static void bnx2x_nic_load_pmf(struct bnx2x *bp, u32 load_code)
+{
+       if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+           (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
+           (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
+               bp->port.pmf = 1;
+               /* We need the barrier to ensure the ordering between the
+                * writing to bp->port.pmf here and reading it from the
+                * bnx2x_periodic_task().
+                */
+               smp_mb();
+       } else {
+               bp->port.pmf = 0;
+       }
+
+       DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
+}
+
+static void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code)
+{
+       if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+            (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
+           (bp->common.shmem2_base)) {
+               if (SHMEM2_HAS(bp, dcc_support))
+                       SHMEM2_WR(bp, dcc_support,
+                                 (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
+                                  SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
+               if (SHMEM2_HAS(bp, afex_driver_support))
+                       SHMEM2_WR(bp, afex_driver_support,
+                                 SHMEM_AFEX_SUPPORTED_VERSION_ONE);
        }
 
-       return true;
+       /* Set AFEX default VLAN tag to an invalid value */
+       bp->afex_def_vlan_tag = -1;
 }
 
 /**
@@ -2028,49 +2308,15 @@ bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
 static void bnx2x_bz_fp(struct bnx2x *bp, int index)
 {
        struct bnx2x_fastpath *fp = &bp->fp[index];
-       struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[index];
 
        int cos;
        struct napi_struct orig_napi = fp->napi;
        struct bnx2x_agg_info *orig_tpa_info = fp->tpa_info;
        /* bzero bnx2x_fastpath contents */
-       if (bp->stats_init) {
-               memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
-               memset(fp, 0, sizeof(*fp));
-       } else {
-               /* Keep Queue statistics */
-               struct bnx2x_eth_q_stats *tmp_eth_q_stats;
-               struct bnx2x_eth_q_stats_old *tmp_eth_q_stats_old;
-
-               tmp_eth_q_stats = kzalloc(sizeof(struct bnx2x_eth_q_stats),
-                                         GFP_KERNEL);
-               if (tmp_eth_q_stats)
-                       memcpy(tmp_eth_q_stats, &fp_stats->eth_q_stats,
-                              sizeof(struct bnx2x_eth_q_stats));
-
-               tmp_eth_q_stats_old =
-                       kzalloc(sizeof(struct bnx2x_eth_q_stats_old),
-                               GFP_KERNEL);
-               if (tmp_eth_q_stats_old)
-                       memcpy(tmp_eth_q_stats_old, &fp_stats->eth_q_stats_old,
-                              sizeof(struct bnx2x_eth_q_stats_old));
-
-               memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
-               memset(fp, 0, sizeof(*fp));
-
-               if (tmp_eth_q_stats) {
-                       memcpy(&fp_stats->eth_q_stats, tmp_eth_q_stats,
-                              sizeof(struct bnx2x_eth_q_stats));
-                       kfree(tmp_eth_q_stats);
-               }
-
-               if (tmp_eth_q_stats_old) {
-                       memcpy(&fp_stats->eth_q_stats_old, tmp_eth_q_stats_old,
-                              sizeof(struct bnx2x_eth_q_stats_old));
-                       kfree(tmp_eth_q_stats_old);
-               }
-
-       }
+       if (fp->tpa_info)
+               memset(fp->tpa_info, 0, ETH_MAX_AGGREGATION_QUEUES_E1H_E2 *
+                      sizeof(struct bnx2x_agg_info));
+       memset(fp, 0, sizeof(*fp));
 
        /* Restore the NAPI object as it has been already initialized */
        fp->napi = orig_napi;
@@ -2116,10 +2362,12 @@ int bnx2x_load_cnic(struct bnx2x *bp)
 
        mutex_init(&bp->cnic_mutex);
 
-       rc = bnx2x_alloc_mem_cnic(bp);
-       if (rc) {
-               BNX2X_ERR("Unable to allocate bp memory for cnic\n");
-               LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
+       if (IS_PF(bp)) {
+               rc = bnx2x_alloc_mem_cnic(bp);
+               if (rc) {
+                       BNX2X_ERR("Unable to allocate bp memory for cnic\n");
+                       LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
+               }
        }
 
        rc = bnx2x_alloc_fp_mem_cnic(bp);
@@ -2146,14 +2394,17 @@ int bnx2x_load_cnic(struct bnx2x *bp)
 
        bnx2x_nic_init_cnic(bp);
 
-       /* Enable Timer scan */
-       REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
+       if (IS_PF(bp)) {
+               /* Enable Timer scan */
+               REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
 
-       for_each_cnic_queue(bp, i) {
-               rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
-               if (rc) {
-                       BNX2X_ERR("Queue setup failed\n");
-                       LOAD_ERROR_EXIT(bp, load_error_cnic2);
+               /* setup cnic queues */
+               for_each_cnic_queue(bp, i) {
+                       rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+                       if (rc) {
+                               BNX2X_ERR("Queue setup failed\n");
+                               LOAD_ERROR_EXIT(bp, load_error_cnic2);
+                       }
                }
        }
 
@@ -2194,13 +2445,11 @@ load_error_cnic0:
 #endif /* ! BNX2X_STOP_ON_ERROR */
 }
 
-
 /* must be called with rtnl_lock */
 int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 {
        int port = BP_PORT(bp);
-       u32 load_code;
-       int i, rc;
+       int i, rc = 0, load_code = 0;
 
        DP(NETIF_MSG_IFUP, "Starting NIC load\n");
        DP(NETIF_MSG_IFUP,
@@ -2215,15 +2464,13 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 
        bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
 
-       /* Set the initial link reported state to link down */
-       bnx2x_acquire_phy_lock(bp);
        memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link));
        __set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
                &bp->last_reported_link.link_report_flags);
-       bnx2x_release_phy_lock(bp);
 
-       /* must be called before memory allocation and HW init */
-       bnx2x_ilt_set_info(bp);
+       if (IS_PF(bp))
+               /* must be called before memory allocation and HW init */
+               bnx2x_ilt_set_info(bp);
 
        /*
         * Zero fastpath structures preserving invariants like napi, which are
@@ -2242,8 +2489,33 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        /* Set the receive queues buffer size */
        bnx2x_set_rx_buf_size(bp);
 
-       if (bnx2x_alloc_mem(bp))
-               return -ENOMEM;
+       if (IS_PF(bp)) {
+               rc = bnx2x_alloc_mem(bp);
+               if (rc) {
+                       BNX2X_ERR("Unable to allocate bp memory\n");
+                       return rc;
+               }
+       }
+
+       /* Allocated memory for FW statistics  */
+       if (bnx2x_alloc_fw_stats_mem(bp))
+               LOAD_ERROR_EXIT(bp, load_error0);
+
+       /* need to be done after alloc mem, since it's self adjusting to amount
+        * of memory available for RSS queues
+        */
+       rc = bnx2x_alloc_fp_mem(bp);
+       if (rc) {
+               BNX2X_ERR("Unable to allocate memory for fps\n");
+               LOAD_ERROR_EXIT(bp, load_error0);
+       }
+
+       /* request pf to initialize status blocks */
+       if (IS_VF(bp)) {
+               rc = bnx2x_vfpf_init(bp);
+               if (rc)
+                       LOAD_ERROR_EXIT(bp, load_error0);
+       }
 
        /* As long as bnx2x_alloc_mem() may possibly update
         * bp->num_queues, bnx2x_set_real_num_queues() should always
@@ -2266,98 +2538,48 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        DP(NETIF_MSG_IFUP, "napi added\n");
        bnx2x_napi_enable(bp);
 
-       /* set pf load just before approaching the MCP */
-       bnx2x_set_pf_load(bp);
-
-       /* Send LOAD_REQUEST command to MCP
-        * Returns the type of LOAD command:
-        * if it is the first port to be initialized
-        * common blocks should be initialized, otherwise - not
-        */
-       if (!BP_NOMCP(bp)) {
-               /* init fw_seq */
-               bp->fw_seq =
-                       (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
-                        DRV_MSG_SEQ_NUMBER_MASK);
-               BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
-
-               /* Get current FW pulse sequence */
-               bp->fw_drv_pulse_wr_seq =
-                       (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
-                        DRV_PULSE_SEQ_MASK);
-               BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
-
-               load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
-                                            DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
-               if (!load_code) {
-                       BNX2X_ERR("MCP response failure, aborting\n");
-                       rc = -EBUSY;
-                       LOAD_ERROR_EXIT(bp, load_error1);
-               }
-               if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
-                       BNX2X_ERR("Driver load refused\n");
-                       rc = -EBUSY; /* other port in diagnostic mode */
-                       LOAD_ERROR_EXIT(bp, load_error1);
-               }
-               if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
-                   load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
-                       /* abort nic load if version mismatch */
-                       if (!bnx2x_test_firmware_version(bp, true)) {
-                               rc = -EBUSY;
+       if (IS_PF(bp)) {
+               /* set pf load just before approaching the MCP */
+               bnx2x_set_pf_load(bp);
+
+               /* if mcp exists send load request and analyze response */
+               if (!BP_NOMCP(bp)) {
+                       /* attempt to load pf */
+                       rc = bnx2x_nic_load_request(bp, &load_code);
+                       if (rc)
+                               LOAD_ERROR_EXIT(bp, load_error1);
+
+                       /* what did mcp say? */
+                       rc = bnx2x_nic_load_analyze_req(bp, load_code);
+                       if (rc) {
+                               bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
                                LOAD_ERROR_EXIT(bp, load_error2);
                        }
+               } else {
+                       load_code = bnx2x_nic_load_no_mcp(bp, port);
                }
 
-       } else {
-               int path = BP_PATH(bp);
-
-               DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d]      %d, %d, %d\n",
-                  path, load_count[path][0], load_count[path][1],
-                  load_count[path][2]);
-               load_count[path][0]++;
-               load_count[path][1 + port]++;
-               DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d]  %d, %d, %d\n",
-                  path, load_count[path][0], load_count[path][1],
-                  load_count[path][2]);
-               if (load_count[path][0] == 1)
-                       load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
-               else if (load_count[path][1 + port] == 1)
-                       load_code = FW_MSG_CODE_DRV_LOAD_PORT;
-               else
-                       load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
-       }
-
-       if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
-           (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
-           (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
-               bp->port.pmf = 1;
-               /*
-                * We need the barrier to ensure the ordering between the
-                * writing to bp->port.pmf here and reading it from the
-                * bnx2x_periodic_task().
-                */
-               smp_mb();
-       } else
-               bp->port.pmf = 0;
-
-       DP(NETIF_MSG_IFUP, "pmf %d\n", bp->port.pmf);
+               /* mark pmf if applicable */
+               bnx2x_nic_load_pmf(bp, load_code);
 
-       /* Init Function state controlling object */
-       bnx2x__init_func_obj(bp);
+               /* Init Function state controlling object */
+               bnx2x__init_func_obj(bp);
 
-       /* Initialize HW */
-       rc = bnx2x_init_hw(bp, load_code);
-       if (rc) {
-               BNX2X_ERR("HW init failed, aborting\n");
-               bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
-               LOAD_ERROR_EXIT(bp, load_error2);
+               /* Initialize HW */
+               rc = bnx2x_init_hw(bp, load_code);
+               if (rc) {
+                       BNX2X_ERR("HW init failed, aborting\n");
+                       bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+                       LOAD_ERROR_EXIT(bp, load_error2);
+               }
        }
 
        /* Connect to IRQs */
        rc = bnx2x_setup_irqs(bp);
        if (rc) {
-               BNX2X_ERR("IRQs setup failed\n");
-               bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+               BNX2X_ERR("setup irqs failed\n");
+               if (IS_PF(bp))
+                       bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
                LOAD_ERROR_EXIT(bp, load_error2);
        }
 
@@ -2365,78 +2587,89 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        bnx2x_nic_init(bp, load_code);
 
        /* Init per-function objects */
-       bnx2x_init_bp_objs(bp);
-
-       if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
-           (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
-           (bp->common.shmem2_base)) {
-               if (SHMEM2_HAS(bp, dcc_support))
-                       SHMEM2_WR(bp, dcc_support,
-                                 (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
-                                  SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
-               if (SHMEM2_HAS(bp, afex_driver_support))
-                       SHMEM2_WR(bp, afex_driver_support,
-                                 SHMEM_AFEX_SUPPORTED_VERSION_ONE);
-       }
+       if (IS_PF(bp)) {
+               bnx2x_init_bp_objs(bp);
+               bnx2x_iov_nic_init(bp);
+
+               /* Set AFEX default VLAN tag to an invalid value */
+               bp->afex_def_vlan_tag = -1;
+               bnx2x_nic_load_afex_dcc(bp, load_code);
+               bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
+               rc = bnx2x_func_start(bp);
+               if (rc) {
+                       BNX2X_ERR("Function start failed!\n");
+                       bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
 
-       /* Set AFEX default VLAN tag to an invalid value */
-       bp->afex_def_vlan_tag = -1;
+                       LOAD_ERROR_EXIT(bp, load_error3);
+               }
 
-       bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
-       rc = bnx2x_func_start(bp);
-       if (rc) {
-               BNX2X_ERR("Function start failed!\n");
-               bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
-               LOAD_ERROR_EXIT(bp, load_error3);
-       }
+               /* Send LOAD_DONE command to MCP */
+               if (!BP_NOMCP(bp)) {
+                       load_code = bnx2x_fw_command(bp,
+                                                    DRV_MSG_CODE_LOAD_DONE, 0);
+                       if (!load_code) {
+                               BNX2X_ERR("MCP response failure, aborting\n");
+                               rc = -EBUSY;
+                               LOAD_ERROR_EXIT(bp, load_error3);
+                       }
+               }
 
-       /* Send LOAD_DONE command to MCP */
-       if (!BP_NOMCP(bp)) {
-               load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
-               if (!load_code) {
-                       BNX2X_ERR("MCP response failure, aborting\n");
-                       rc = -EBUSY;
+               /* setup the leading queue */
+               rc = bnx2x_setup_leading(bp);
+               if (rc) {
+                       BNX2X_ERR("Setup leading failed!\n");
                        LOAD_ERROR_EXIT(bp, load_error3);
                }
-       }
 
-       rc = bnx2x_setup_leading(bp);
-       if (rc) {
-               BNX2X_ERR("Setup leading failed!\n");
-               LOAD_ERROR_EXIT(bp, load_error3);
-       }
+               /* set up the rest of the queues */
+               for_each_nondefault_eth_queue(bp, i) {
+                       rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+                       if (rc) {
+                               BNX2X_ERR("Queue setup failed\n");
+                               LOAD_ERROR_EXIT(bp, load_error3);
+                       }
+               }
 
-       for_each_nondefault_eth_queue(bp, i) {
-               rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+               /* setup rss */
+               rc = bnx2x_init_rss_pf(bp);
                if (rc) {
-                       BNX2X_ERR("Queue setup failed\n");
+                       BNX2X_ERR("PF RSS init failed\n");
                        LOAD_ERROR_EXIT(bp, load_error3);
                }
-       }
 
-       rc = bnx2x_init_rss_pf(bp);
-       if (rc) {
-               BNX2X_ERR("PF RSS init failed\n");
-               LOAD_ERROR_EXIT(bp, load_error3);
+       } else { /* vf */
+               for_each_eth_queue(bp, i) {
+                       rc = bnx2x_vfpf_setup_q(bp, i);
+                       if (rc) {
+                               BNX2X_ERR("Queue setup failed\n");
+                               LOAD_ERROR_EXIT(bp, load_error3);
+                       }
+               }
        }
 
        /* Now when Clients are configured we are ready to work */
        bp->state = BNX2X_STATE_OPEN;
 
        /* Configure a ucast MAC */
-       rc = bnx2x_set_eth_mac(bp, true);
+       if (IS_PF(bp))
+               rc = bnx2x_set_eth_mac(bp, true);
+       else /* vf */
+               rc = bnx2x_vfpf_set_mac(bp);
        if (rc) {
                BNX2X_ERR("Setting Ethernet MAC failed\n");
                LOAD_ERROR_EXIT(bp, load_error3);
        }
 
-       if (bp->pending_max) {
+       if (IS_PF(bp) && bp->pending_max) {
                bnx2x_update_max_mf_config(bp, bp->pending_max);
                bp->pending_max = 0;
        }
 
-       if (bp->port.pmf)
-               bnx2x_initial_phy_init(bp, load_mode);
+       if (bp->port.pmf) {
+               rc = bnx2x_initial_phy_init(bp, load_mode);
+               if (rc)
+                       LOAD_ERROR_EXIT(bp, load_error3);
+       }
        bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN;
 
        /* Start fast path */
@@ -2478,8 +2711,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        if (CNIC_ENABLED(bp))
                bnx2x_load_cnic(bp);
 
-       /* mark driver is loaded in shmem2 */
-       if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
+       if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
+               /* mark driver is loaded in shmem2 */
                u32 val;
                val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
                SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
@@ -2488,7 +2721,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        }
 
        /* Wait for all pending SP commands to complete */
-       if (!bnx2x_wait_sp_comp(bp, ~0x0UL)) {
+       if (IS_PF(bp) && !bnx2x_wait_sp_comp(bp, ~0x0UL)) {
                BNX2X_ERR("Timeout waiting for SP elements to complete\n");
                bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
                return -EBUSY;
@@ -2504,10 +2737,12 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 
 #ifndef BNX2X_STOP_ON_ERROR
 load_error3:
-       bnx2x_int_disable_sync(bp, 1);
+       if (IS_PF(bp)) {
+               bnx2x_int_disable_sync(bp, 1);
 
-       /* Clean queueable objects */
-       bnx2x_squeeze_objects(bp);
+               /* Clean queueable objects */
+               bnx2x_squeeze_objects(bp);
+       }
 
        /* Free SKBs, SGEs, TPA pool and driver internals */
        bnx2x_free_skbs(bp);
@@ -2517,7 +2752,7 @@ load_error3:
        /* Release IRQs */
        bnx2x_free_irq(bp);
 load_error2:
-       if (!BP_NOMCP(bp)) {
+       if (IS_PF(bp) && !BP_NOMCP(bp)) {
                bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
                bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
        }
@@ -2525,15 +2760,35 @@ load_error2:
        bp->port.pmf = 0;
 load_error1:
        bnx2x_napi_disable(bp);
+
        /* clear pf_load status, as it was already set */
-       bnx2x_clear_pf_load(bp);
+       if (IS_PF(bp))
+               bnx2x_clear_pf_load(bp);
 load_error0:
+       bnx2x_free_fp_mem(bp);
+       bnx2x_free_fw_stats_mem(bp);
        bnx2x_free_mem(bp);
 
        return rc;
 #endif /* ! BNX2X_STOP_ON_ERROR */
 }
 
+static int bnx2x_drain_tx_queues(struct bnx2x *bp)
+{
+       u8 rc = 0, cos, i;
+
+       /* Wait until tx fastpath tasks complete */
+       for_each_tx_queue(bp, i) {
+               struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               for_each_cos_in_tx_queue(fp, cos)
+                       rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
+
 /* must be called with rtnl_lock */
 int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
 {
@@ -2543,15 +2798,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
        DP(NETIF_MSG_IFUP, "Starting NIC unload\n");
 
        /* mark driver is unloaded in shmem2 */
-       if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
+       if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
                u32 val;
                val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
                SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
                          val & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
        }
 
-       if ((bp->state == BNX2X_STATE_CLOSED) ||
-           (bp->state == BNX2X_STATE_ERROR)) {
+       if (IS_PF(bp) && bp->recovery_state != BNX2X_RECOVERY_DONE &&
+           (bp->state == BNX2X_STATE_CLOSED ||
+            bp->state == BNX2X_STATE_ERROR)) {
                /* We can get here if the driver has been unloaded
                 * during parity error recovery and is either waiting for a
                 * leader to complete or for other functions to unload and
@@ -2569,8 +2825,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
                return -EINVAL;
        }
 
-       /*
-        * It's important to set the bp->state to the value different from
+       /* Nothing to do during unload if previous bnx2x_nic_load()
+        * have not completed succesfully - all resourses are released.
+        *
+        * we can get here only after unsuccessful ndo_* callback, during which
+        * dev->IFF_UP flag is still on.
+        */
+       if (bp->state == BNX2X_STATE_CLOSED || bp->state == BNX2X_STATE_ERROR)
+               return 0;
+
+       /* It's important to set the bp->state to the value different from
         * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int()
         * may restart the Tx from the NAPI context (see bnx2x_tx_int()).
         */
@@ -2588,16 +2852,24 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
 
        del_timer_sync(&bp->timer);
 
-       /* Set ALWAYS_ALIVE bit in shmem */
-       bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
-
-       bnx2x_drv_pulse(bp);
+       if (IS_PF(bp)) {
+               /* Set ALWAYS_ALIVE bit in shmem */
+               bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
+               bnx2x_drv_pulse(bp);
+               bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+               bnx2x_save_statistics(bp);
+       }
 
-       bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-       bnx2x_save_statistics(bp);
+       /* wait till consumers catch up with producers in all queues */
+       bnx2x_drain_tx_queues(bp);
 
-       /* Cleanup the chip if needed */
-       if (unload_mode != UNLOAD_RECOVERY)
+       /* if VF indicate to PF this function is going down (PF will delete sp
+        * elements and clear initializations
+        */
+       if (IS_VF(bp))
+               bnx2x_vfpf_close_vf(bp);
+       else if (unload_mode != UNLOAD_RECOVERY)
+               /* if this is a normal/close unload need to clean up chip*/
                bnx2x_chip_cleanup(bp, unload_mode, keep_link);
        else {
                /* Send the UNLOAD_REQUEST to the MCP */
@@ -2630,7 +2902,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
         * At this stage no more interrupts will arrive so we may safly clean
         * the queueable objects here in case they failed to get cleaned so far.
         */
-       bnx2x_squeeze_objects(bp);
+       if (IS_PF(bp))
+               bnx2x_squeeze_objects(bp);
 
        /* There should be no more pending SP commands at this stage */
        bp->sp_state = 0;
@@ -2644,19 +2917,22 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
        for_each_rx_queue(bp, i)
                bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
 
-       if (CNIC_LOADED(bp)) {
+       bnx2x_free_fp_mem(bp);
+       if (CNIC_LOADED(bp))
                bnx2x_free_fp_mem_cnic(bp);
-               bnx2x_free_mem_cnic(bp);
-       }
-       bnx2x_free_mem(bp);
 
+       if (IS_PF(bp)) {
+               bnx2x_free_mem(bp);
+               if (CNIC_LOADED(bp))
+                       bnx2x_free_mem_cnic(bp);
+       }
        bp->state = BNX2X_STATE_CLOSED;
        bp->cnic_loaded = false;
 
        /* Check if there are pending parity attentions. If there are - set
         * RECOVERY_IN_PROGRESS.
         */
-       if (bnx2x_chk_parity_attn(bp, &global, false)) {
+       if (IS_PF(bp) && bnx2x_chk_parity_attn(bp, &global, false)) {
                bnx2x_set_reset_in_progress(bp);
 
                /* Set RESET_IS_GLOBAL if needed */
@@ -2668,7 +2944,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
        /* The last driver must disable a "close the gate" if there is no
         * parity attention or "process kill" pending.
         */
-       if (!bnx2x_clear_pf_load(bp) && bnx2x_reset_is_done(bp, BP_PATH(bp)))
+       if (IS_PF(bp) &&
+           !bnx2x_clear_pf_load(bp) &&
+           bnx2x_reset_is_done(bp, BP_PATH(bp)))
                bnx2x_disable_close_the_gate(bp);
 
        DP(NETIF_MSG_IFUP, "Ending NIC unload\n");
@@ -2752,7 +3030,6 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
                        if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
                                bnx2x_tx_int(bp, fp->txdata_ptr[cos]);
 
-
                if (bnx2x_has_rx_work(fp)) {
                        work_done += bnx2x_rx_int(fp, budget - work_done);
 
@@ -2851,17 +3128,21 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
        return bd_prod;
 }
 
-static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
+#define bswab32(b32) ((__force __le32) swab32((__force __u32) (b32)))
+#define bswab16(b16) ((__force __le16) swab16((__force __u16) (b16)))
+static inline __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
 {
+       __sum16 tsum = (__force __sum16) csum;
+
        if (fix > 0)
-               csum = (u16) ~csum_fold(csum_sub(csum,
-                               csum_partial(t_header - fix, fix, 0)));
+               tsum = ~csum_fold(csum_sub((__force __wsum) csum,
+                                 csum_partial(t_header - fix, fix, 0)));
 
        else if (fix < 0)
-               csum = (u16) ~csum_fold(csum_add(csum,
-                               csum_partial(t_header, -fix, 0)));
+               tsum = ~csum_fold(csum_add((__force __wsum) csum,
+                                 csum_partial(t_header, -fix, 0)));
 
-       return swab16(csum);
+       return bswab16(csum);
 }
 
 static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
@@ -2995,23 +3276,24 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
                                     u32 xmit_type)
 {
        pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
-       pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
+       pbd->tcp_send_seq = bswab32(tcp_hdr(skb)->seq);
        pbd->tcp_flags = pbd_tcp_flags(skb);
 
        if (xmit_type & XMIT_GSO_V4) {
-               pbd->ip_id = swab16(ip_hdr(skb)->id);
+               pbd->ip_id = bswab16(ip_hdr(skb)->id);
                pbd->tcp_pseudo_csum =
-                       swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-                                                 ip_hdr(skb)->daddr,
-                                                 0, IPPROTO_TCP, 0));
+                       bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+                                                  ip_hdr(skb)->daddr,
+                                                  0, IPPROTO_TCP, 0));
 
        } else
                pbd->tcp_pseudo_csum =
-                       swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                               &ipv6_hdr(skb)->daddr,
-                                               0, IPPROTO_TCP, 0));
+                       bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                                &ipv6_hdr(skb)->daddr,
+                                                0, IPPROTO_TCP, 0));
 
-       pbd->global_data |= ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN;
+       pbd->global_data |=
+               cpu_to_le16(ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN);
 }
 
 /**
@@ -3025,12 +3307,12 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
  * 57712 related
  */
 static inline  u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
-       u32 *parsing_data, u32 xmit_type)
+                                       u32 *parsing_data, u32 xmit_type)
 {
        *parsing_data |=
-                       ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
-                       ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
-                       ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
+               ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
+               ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
+               ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
 
        if (xmit_type & XMIT_CSUM_TCP) {
                *parsing_data |= ((tcp_hdrlen(skb) / 4) <<
@@ -3038,12 +3320,11 @@ static inline  u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
                        ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
 
                return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
-       } else
-               /* We support checksum offload for TCP and UDP only.
-                * No need to pass the UDP header length - it's a constant.
-                */
-               return skb_transport_header(skb) +
-                               sizeof(struct udphdr) - skb->data;
+       }
+       /* We support checksum offload for TCP and UDP only.
+        * No need to pass the UDP header length - it's a constant.
+        */
+       return skb_transport_header(skb) + sizeof(struct udphdr) - skb->data;
 }
 
 static inline void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb,
@@ -3078,8 +3359,9 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
 
        /* for now NS flag is not used in Linux */
        pbd->global_data =
-               (hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
-                        ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
+               cpu_to_le16(hlen |
+                           ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
+                            ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
 
        pbd->ip_hlen_w = (skb_transport_header(skb) -
                        skb_network_header(skb)) >> 1;
@@ -3096,7 +3378,7 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
        hlen = hlen*2;
 
        if (xmit_type & XMIT_CSUM_TCP) {
-               pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
+               pbd->tcp_pseudo_csum = bswab16(tcp_hdr(skb)->check);
 
        } else {
                s8 fix = SKB_CS_OFF(skb); /* signed! */
@@ -3176,17 +3458,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        dev_kfree_skb(skb);
                        return NETDEV_TX_OK;
                }
-                       bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
-                       netif_tx_stop_queue(txq);
+               bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
+               netif_tx_stop_queue(txq);
                BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
 
                return NETDEV_TX_BUSY;
        }
 
        DP(NETIF_MSG_TX_QUEUED,
-          "queue[%d]: SKB: summed %x  protocol %x protocol(%x,%x) gso type %x  xmit_type %x\n",
+          "queue[%d]: SKB: summed %x  protocol %x protocol(%x,%x) gso type %x  xmit_type %x len %d\n",
           txq_index, skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
-          ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
+          ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type,
+          skb->len);
 
        eth = (struct ethhdr *)skb->data;
 
@@ -3267,8 +3550,22 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                    cpu_to_le16(vlan_tx_tag_get(skb));
                tx_start_bd->bd_flags.as_bitfield |=
                    (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
-       } else
-               tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+       } else {
+               /* when transmitting in a vf, start bd must hold the ethertype
+                * for fw to enforce it
+                */
+#ifndef BNX2X_STOP_ON_ERROR
+               if (IS_VF(bp)) {
+#endif
+                       tx_start_bd->vlan_or_ethertype =
+                               cpu_to_le16(ntohs(eth->h_proto));
+#ifndef BNX2X_STOP_ON_ERROR
+               } else {
+                       /* used by FW for packet accounting */
+                       tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+               }
+#endif
+       }
 
        /* turn on parsing and get a BD */
        bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
@@ -3284,9 +3581,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        hlen = bnx2x_set_pbd_csum_e2(bp, skb,
                                                     &pbd_e2_parsing_data,
                                                     xmit_type);
-               if (IS_MF_SI(bp)) {
-                       /*
-                        * fill in the MAC addresses in the PBD - for local
+
+               if (IS_MF_SI(bp) || IS_VF(bp)) {
+                       /* fill in the MAC addresses in the PBD - for local
                         * switching
                         */
                        bnx2x_set_fw_mac_addr(&pbd_e2->src_mac_addr_hi,
@@ -3567,7 +3864,6 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p)
                        return rc;
        }
 
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
        if (netif_running(dev))
@@ -3763,6 +4059,8 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
        } else /* if rx_ring_size specified - use it */
                rx_ring_size = bp->rx_ring_size;
 
+       DP(BNX2X_MSG_SP, "calculated rx_ring_size %d\n", rx_ring_size);
+
        /* Common */
        sb = &bnx2x_fp(bp, index, status_blk);
 
@@ -3909,7 +4207,10 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp)
 
 void bnx2x_free_mem_bp(struct bnx2x *bp)
 {
-       kfree(bp->fp->tpa_info);
+       int i;
+
+       for (i = 0; i < bp->fp_array_size; i++)
+               kfree(bp->fp[i].tpa_info);
        kfree(bp->fp);
        kfree(bp->sp_objs);
        kfree(bp->fp_stats);
@@ -3929,18 +4230,22 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp)
 
        /*
         * The biggest MSI-X table we might need is as a maximum number of fast
-        * path IGU SBs plus default SB (for PF).
+        * path IGU SBs plus default SB (for PF only).
         */
-       msix_table_size = bp->igu_sb_cnt + 1;
+       msix_table_size = bp->igu_sb_cnt;
+       if (IS_PF(bp))
+               msix_table_size++;
+       BNX2X_DEV_INFO("msix_table_size %d\n", msix_table_size);
 
        /* fp array: RSS plus CNIC related L2 queues */
        fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + CNIC_SUPPORT(bp);
-       BNX2X_DEV_INFO("fp_array_size %d", fp_array_size);
+       bp->fp_array_size = fp_array_size;
+       BNX2X_DEV_INFO("fp_array_size %d\n", bp->fp_array_size);
 
-       fp = kcalloc(fp_array_size, sizeof(*fp), GFP_KERNEL);
+       fp = kcalloc(bp->fp_array_size, sizeof(*fp), GFP_KERNEL);
        if (!fp)
                goto alloc_err;
-       for (i = 0; i < fp_array_size; i++) {
+       for (i = 0; i < bp->fp_array_size; i++) {
                fp[i].tpa_info =
                        kcalloc(ETH_MAX_AGGREGATION_QUEUES_E1H_E2,
                                sizeof(struct bnx2x_agg_info), GFP_KERNEL);
@@ -3951,13 +4256,13 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp)
        bp->fp = fp;
 
        /* allocate sp objs */
-       bp->sp_objs = kcalloc(fp_array_size, sizeof(struct bnx2x_sp_objs),
+       bp->sp_objs = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_sp_objs),
                              GFP_KERNEL);
        if (!bp->sp_objs)
                goto alloc_err;
 
        /* allocate fp_stats */
-       bp->fp_stats = kcalloc(fp_array_size, sizeof(struct bnx2x_fp_stats),
+       bp->fp_stats = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_fp_stats),
                               GFP_KERNEL);
        if (!bp->fp_stats)
                goto alloc_err;
@@ -4036,7 +4341,7 @@ int bnx2x_get_link_cfg_idx(struct bnx2x *bp)
 {
        u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp);
        /*
-        * The selected actived PHY is always after swapping (in case PHY
+        * The selected activated PHY is always after swapping (in case PHY
         * swapping is enabled). So when swapping is enabled, we need to reverse
         * the configuration
         */
index 0991534f61da18b276fd3d602259371cba84f87a..aee7671ff4c10bd55eda3a4b93a82e083ffaeb86 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_cmn.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
 
 
 #include "bnx2x.h"
+#include "bnx2x_sriov.h"
 
 /* This is used as a replacement for an MCP if it's not present */
 extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */
@@ -196,6 +197,7 @@ void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment,
 
 /* Disable transactions from chip to host */
 void bnx2x_pf_disable(struct bnx2x *bp);
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val);
 
 /**
  * bnx2x__link_status_update - handles link status change.
@@ -401,7 +403,7 @@ void bnx2x_set_rx_mode(struct net_device *dev);
  * If bp->state is OPEN, should be called with
  * netif_addr_lock_bh().
  */
-void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
 
 /**
  * bnx2x_set_q_rx_mode - configures rx_mode for a single queue.
@@ -413,11 +415,11 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
  * @tx_accept_flags:   tx accept configuration (tx switch)
  * @ramrod_flags:      ramrod configuration
  */
-void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
-                        unsigned long rx_mode_flags,
-                        unsigned long rx_accept_flags,
-                        unsigned long tx_accept_flags,
-                        unsigned long ramrod_flags);
+int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+                       unsigned long rx_mode_flags,
+                       unsigned long rx_accept_flags,
+                       unsigned long tx_accept_flags,
+                       unsigned long ramrod_flags);
 
 /* Parity errors related */
 void bnx2x_set_pf_load(struct bnx2x *bp);
@@ -477,8 +479,6 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
  */
 void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value);
 /* Error handling */
-void bnx2x_panic_dump(struct bnx2x *bp);
-
 void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl);
 
 /* validate currect fw is loaded */
@@ -496,9 +496,44 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
 /* setup_tc callback */
 int bnx2x_setup_tc(struct net_device *dev, u8 num_tc);
 
+int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);
+
 /* select_queue callback */
 u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);
 
+static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
+                                       struct bnx2x_fastpath *fp,
+                                       u16 bd_prod, u16 rx_comp_prod,
+                                       u16 rx_sge_prod)
+{
+       struct ustorm_eth_rx_producers rx_prods = {0};
+       u32 i;
+
+       /* Update producers */
+       rx_prods.bd_prod = bd_prod;
+       rx_prods.cqe_prod = rx_comp_prod;
+       rx_prods.sge_prod = rx_sge_prod;
+
+       /* Make sure that the BD and SGE data is updated before updating the
+        * producers since FW might read the BD/SGE right after the producer
+        * is updated.
+        * This is only applicable for weak-ordered memory model archs such
+        * as IA-64. The following barrier is also mandatory since FW will
+        * assumes BDs must have buffers.
+        */
+       wmb();
+
+       for (i = 0; i < sizeof(rx_prods)/4; i++)
+               REG_WR(bp, fp->ustorm_rx_prods_offset + i*4,
+                      ((u32 *)&rx_prods)[i]);
+
+       mmiowb(); /* keep prod updates ordered */
+
+       DP(NETIF_MSG_RX_STATUS,
+          "queue[%d]:  wrote  bd_prod %u  cqe_prod %u  sge_prod %u\n",
+          fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
+}
+
 /* reload helper */
 int bnx2x_reload_if_running(struct net_device *dev);
 
@@ -507,9 +542,6 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p);
 /* NAPI poll Rx part */
 int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
 
-void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-                       u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod);
-
 /* NAPI poll Tx part */
 int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata);
 
@@ -612,38 +644,6 @@ static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
        fp->fp_hc_idx = fp->sb_running_index[SM_RX_ID];
 }
 
-static inline void bnx2x_update_rx_prod_gen(struct bnx2x *bp,
-                       struct bnx2x_fastpath *fp, u16 bd_prod,
-                       u16 rx_comp_prod, u16 rx_sge_prod, u32 start)
-{
-       struct ustorm_eth_rx_producers rx_prods = {0};
-       u32 i;
-
-       /* Update producers */
-       rx_prods.bd_prod = bd_prod;
-       rx_prods.cqe_prod = rx_comp_prod;
-       rx_prods.sge_prod = rx_sge_prod;
-
-       /*
-        * Make sure that the BD and SGE data is updated before updating the
-        * producers since FW might read the BD/SGE right after the producer
-        * is updated.
-        * This is only applicable for weak-ordered memory model archs such
-        * as IA-64. The following barrier is also mandatory since FW will
-        * assumes BDs must have buffers.
-        */
-       wmb();
-
-       for (i = 0; i < sizeof(rx_prods)/4; i++)
-               REG_WR(bp, start + i*4, ((u32 *)&rx_prods)[i]);
-
-       mmiowb(); /* keep prod updates ordered */
-
-       DP(NETIF_MSG_RX_STATUS,
-          "queue[%d]:  wrote  bd_prod %u  cqe_prod %u  sge_prod %u\n",
-          fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
-}
-
 static inline void bnx2x_igu_ack_sb_gen(struct bnx2x *bp, u8 igu_sb_id,
                                        u8 segment, u16 index, u8 op,
                                        u8 update, u32 igu_addr)
@@ -819,7 +819,7 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
                return;
 
        dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
-                      SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+                      SGE_PAGES, DMA_FROM_DEVICE);
        __free_pages(page, PAGES_PER_SGE_SHIFT);
 
        sw_buf->page = NULL;
@@ -863,7 +863,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
                netif_napi_del(&bnx2x_fp(bp, i, napi));
 }
 
-void bnx2x_set_int_mode(struct bnx2x *bp);
+int bnx2x_set_int_mode(struct bnx2x *bp);
 
 static inline void bnx2x_disable_msi(struct bnx2x *bp)
 {
@@ -973,7 +973,6 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
        return bnx2x_func_state_change(bp, &func_params);
 }
 
-
 /**
  * bnx2x_set_fw_mac_addr - fill in a MAC address in FW format
  *
@@ -982,8 +981,8 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
  * @fw_lo:     pointer to lower part
  * @mac:       pointer to MAC address
  */
-static inline void bnx2x_set_fw_mac_addr(u16 *fw_hi, u16 *fw_mid, u16 *fw_lo,
-                                        u8 *mac)
+static inline void bnx2x_set_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid,
+                                        __le16 *fw_lo, u8 *mac)
 {
        ((u8 *)fw_hi)[0]  = mac[1];
        ((u8 *)fw_hi)[1]  = mac[0];
@@ -1108,6 +1107,9 @@ static inline void bnx2x_init_bp_objs(struct bnx2x *bp)
        bnx2x_init_mac_credit_pool(bp, &bp->macs_pool, BP_FUNC(bp),
                                   bnx2x_get_path_func_num(bp));
 
+       bnx2x_init_vlan_credit_pool(bp, &bp->vlans_pool, BP_ABS_FUNC(bp)>>1,
+                                   bnx2x_get_path_func_num(bp));
+
        /* RSS configuration object */
        bnx2x_init_rss_config_obj(bp, &bp->rss_conf_obj, bp->fp->cl_id,
                                  bp->fp->cid, BP_FUNC(bp), BP_FUNC(bp),
@@ -1125,15 +1127,7 @@ static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp)
                return fp->cl_id;
 }
 
-static inline u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
-{
-       struct bnx2x *bp = fp->bp;
-
-       if (!CHIP_IS_E1x(bp))
-               return USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
-       else
-               return USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
-}
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
 
 static inline void bnx2x_init_txdata(struct bnx2x *bp,
                                     struct bnx2x_fp_txdata *txdata, u32 cid,
@@ -1228,7 +1222,7 @@ static inline int bnx2x_clean_tx_queue(struct bnx2x *bp,
 #endif
                }
                cnt--;
-               usleep_range(1000, 1000);
+               usleep_range(1000, 2000);
        }
 
        return 0;
@@ -1263,7 +1257,7 @@ static inline bool bnx2x_wait_sp_comp(struct bnx2x *bp, unsigned long mask)
                }
                netif_addr_unlock_bh(bp->dev);
 
-               usleep_range(1000, 1000);
+               usleep_range(1000, 2000);
        }
 
        smp_mb();
@@ -1393,4 +1387,13 @@ static inline bool bnx2x_is_valid_ether_addr(struct bnx2x *bp, u8 *addr)
        return false;
 }
 
+/**
+ * bnx2x_fill_fw_str - Fill buffer with FW version string
+ *
+ * @bp:        driver handle
+ * @buf:       character buffer to fill with the fw name
+ * @buf_len:   length of the above buffer
+ *
+ */
+void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
 #endif /* BNX2X_CMN_H */
index 10bc093d2ca43d9c0dd9ae309734279ccf1661bb..568205436a15f4d5b37528eb155df6e00ee3f07c 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_dcb.c: Broadcom Everest network driver.
  *
- * Copyright 2009-2012 Broadcom Corporation
+ * Copyright 2009-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -416,6 +416,7 @@ static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
        int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&
                             GET_FLAGS(SHMEM2_RD(bp, drv_flags),
                                       1 << DRV_FLAGS_DCB_MFW_CONFIGURED);
+
        if (bp->dcbx_port_params.pfc.enabled &&
            (!(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) || mfw_configured))
                /*
@@ -558,6 +559,7 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
        int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&
                             GET_FLAGS(SHMEM2_RD(bp, drv_flags),
                                       1 << DRV_FLAGS_DCB_MFW_CONFIGURED);
+
        bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
 
        if (!bp->dcbx_port_params.ets.enabled ||
@@ -1904,11 +1906,13 @@ static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state)
        struct bnx2x *bp = netdev_priv(netdev);
        DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off");
 
+       /* Fail to set state to "enabled" if dcbx is disabled in nvram */
        if (state && ((bp->dcbx_enabled == BNX2X_DCBX_ENABLED_OFF) ||
                      (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_INVALID))) {
                DP(BNX2X_MSG_DCB, "Can not set dcbx to enabled while it is disabled in nvm\n");
                return 1;
        }
+
        bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled);
        return 0;
 }
@@ -2052,7 +2056,6 @@ static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,
        if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES)
                return;
 
-
        if (setting) {
                bp->dcbx_config_params.admin_pfc_bitmap |= (1 << prio);
                bp->dcbx_config_params.admin_pfc_tx_enable = 1;
index 06c7a043594809dd254f48b7a6250c662d5084d3..d153f44cf8f99540c3988a1dd76ca777c10d5fcd 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_dcb.h: Broadcom Everest network driver.
  *
- * Copyright 2009-2012 Broadcom Corporation
+ * Copyright 2009-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
index b926f58e983bbfe083e004c362df6203efb17a3e..bff5e33eaa1496bc6d9b93d58b2cfc4ef40fbbd6 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_dump.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2012 Broadcom Corporation
+ * Copyright (c) 2012-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
 #ifndef BNX2X_DUMP_H
 #define BNX2X_DUMP_H
 
+/* WaitP Definitions */
+#define DRV_DUMP_XSTORM_WAITP_ADDRESS    0x2b8a80
+#define DRV_DUMP_TSTORM_WAITP_ADDRESS    0x1b8a80
+#define DRV_DUMP_USTORM_WAITP_ADDRESS    0x338a80
+#define DRV_DUMP_CSTORM_WAITP_ADDRESS    0x238a80
 
 
-/*definitions */
-#define XSTORM_WAITP_ADDR      0x2b8a80
-#define TSTORM_WAITP_ADDR      0x1b8a80
-#define USTORM_WAITP_ADDR      0x338a80
-#define CSTORM_WAITP_ADDR      0x238a80
-#define TSTORM_CAM_MODE        0x1B1440
+/* Possible Chips */
+#define DUMP_CHIP_E1 1
+#define DUMP_CHIP_E1H 2
+#define DUMP_CHIP_E2 4
+#define DUMP_CHIP_E3A0 8
+#define DUMP_CHIP_E3B0 16
+#define DUMP_PATH_0 512
+#define DUMP_PATH_1 1024
+#define NUM_PRESETS 13
+#define NUM_CHIPS 5
 
-#define MAX_TIMER_PENDING      200
-#define TIMER_SCAN_DONT_CARE   0xFF
-#define RI_E1                          0x1
-#define RI_E1H                         0x2
-#define RI_E2                          0x4
-#define RI_E3                          0x8
-#define RI_E3B0                                0x10
-#define RI_ONLINE                      0x100
-#define RI_OFFLINE                     0x0
-#define RI_PATH0_DUMP                  0x200
-#define RI_PATH1_DUMP                  0x400
-
-#define RI_E1_ONLINE           (RI_E1 | RI_ONLINE)
-#define RI_E1H_ONLINE          (RI_E1H | RI_ONLINE)
-#define RI_E1E1H_ONLINE                (RI_E1 | RI_E1H | RI_ONLINE)
-#define RI_E2_ONLINE           (RI_E2 | RI_ONLINE)
-#define RI_E1E2_ONLINE         (RI_E1 | RI_E2 | RI_ONLINE)
-#define RI_E1HE2_ONLINE                (RI_E1H | RI_E2 | RI_ONLINE)
-#define RI_E1E1HE2_ONLINE      (RI_E1 | RI_E1H | RI_E2 | RI_ONLINE)
-#define RI_E3_ONLINE           (RI_E3 | RI_ONLINE)
-#define RI_E1E3_ONLINE         (RI_E1 | RI_E3 | RI_ONLINE)
-#define RI_E1HE3_ONLINE                (RI_E1H | RI_E3 | RI_ONLINE)
-#define RI_E1E1HE3_ONLINE      (RI_E1 | RI_E1H | RI_E3 | RI_ONLINE)
-#define RI_E2E3_ONLINE         (RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1E2E3_ONLINE       (RI_E1 | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1HE2E3_ONLINE      (RI_E1H | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1E1HE2E3_ONLINE    (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E3B0_ONLINE         (RI_E3B0 | RI_ONLINE)
-#define RI_E1E3B0_ONLINE       (RI_E1 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE3B0_ONLINE      (RI_E1H | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE3B0_ONLINE    (RI_E1 | RI_E1H | RI_E3B0 | RI_ONLINE)
-#define RI_E2E3B0_ONLINE       (RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E2E3B0_ONLINE     (RI_E1 | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE2E3B0_ONLINE    (RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE2E3B0_ONLINE  (RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E3E3B0_ONLINE       (RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E3E3B0_ONLINE     (RI_E1 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE3E3B0_ONLINE    (RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE3E3B0_ONLINE  (RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E2E3E3B0_ONLINE     (RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E2E3E3B0_ONLINE   (RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE2E3E3B0_ONLINE  (RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE2E3E3B0_ONLINE        \
-       (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1_OFFLINE          (RI_E1 | RI_OFFLINE)
-#define RI_E1H_OFFLINE         (RI_E1H | RI_OFFLINE)
-#define RI_E1E1H_OFFLINE       (RI_E1 | RI_E1H | RI_OFFLINE)
-#define RI_E2_OFFLINE          (RI_E2 | RI_OFFLINE)
-#define RI_E1E2_OFFLINE                (RI_E1 | RI_E2 | RI_OFFLINE)
-#define RI_E1HE2_OFFLINE       (RI_E1H | RI_E2 | RI_OFFLINE)
-#define RI_E1E1HE2_OFFLINE     (RI_E1 | RI_E1H | RI_E2 | RI_OFFLINE)
-#define RI_E3_OFFLINE          (RI_E3 | RI_OFFLINE)
-#define RI_E1E3_OFFLINE                (RI_E1 | RI_E3 | RI_OFFLINE)
-#define RI_E1HE3_OFFLINE       (RI_E1H | RI_E3 | RI_OFFLINE)
-#define RI_E1E1HE3_OFFLINE     (RI_E1 | RI_E1H | RI_E3 | RI_OFFLINE)
-#define RI_E2E3_OFFLINE                (RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1E2E3_OFFLINE      (RI_E1 | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1HE2E3_OFFLINE     (RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1E1HE2E3_OFFLINE   (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E3B0_OFFLINE                (RI_E3B0 | RI_OFFLINE)
-#define RI_E1E3B0_OFFLINE      (RI_E1 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE3B0_OFFLINE     (RI_E1H | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE3B0_OFFLINE   (RI_E1 | RI_E1H | RI_E3B0 | RI_OFFLINE)
-#define RI_E2E3B0_OFFLINE      (RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E2E3B0_OFFLINE    (RI_E1 | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE2E3B0_OFFLINE   (RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE2E3B0_OFFLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E3E3B0_OFFLINE      (RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E3E3B0_OFFLINE    (RI_E1 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE3E3B0_OFFLINE   (RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE3E3B0_OFFLINE (RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E2E3E3B0_OFFLINE    (RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E2E3E3B0_OFFLINE  (RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE2E3E3B0_OFFLINE (RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE2E3E3B0_OFFLINE       \
-       (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_ALL_ONLINE          RI_E1E1HE2E3E3B0_ONLINE
-#define RI_ALL_OFFLINE         RI_E1E1HE2E3E3B0_OFFLINE
-
-#define DBG_DMP_TRACE_BUFFER_SIZE      0x800
-#define DBG_DMP_TRACE_BUFFER_OFFSET(shmem0_offset) \
-       ((shmem0_offset) - DBG_DMP_TRACE_BUFFER_SIZE)
-
-struct dump_sign {
-       u32 time_stamp;
-       u32 diag_ver;
-       u32 grc_dump_ver;
-};
-
-struct dump_hdr {
-       u32  hdr_size;  /* in dwords, excluding this field */
-       struct dump_sign        dump_sign;
-       u32  xstorm_waitp;
-       u32  tstorm_waitp;
-       u32  ustorm_waitp;
-       u32  cstorm_waitp;
-       u16  info;
-       u8   idle_chk;
-       u8   reserved;
+struct dump_header {
+       u32 header_size; /* Size in DWORDs excluding this field */
+       u32 version;
+       u32 preset;
+       u32 dump_meta_data; /* OR of CHIP and PATH. */
 };
 
+#define BNX2X_DUMP_VERSION 0x50acff01
 struct reg_addr {
        u32 addr;
        u32 size;
-       u16 info;
+       u32 chips;
+       u32 presets;
 };
 
 struct wreg_addr {
@@ -143,1005 +60,2168 @@ struct wreg_addr {
        u32 size;
        u32 read_regs_count;
        const u32 *read_regs;
-       u16 info;
+       u32 chips;
+       u32 presets;
+};
+
+#define PAGE_MODE_VALUES_E2 2
+#define PAGE_READ_REGS_E2 1
+#define PAGE_WRITE_REGS_E2 1
+static const u32 page_vals_e2[] = {0, 128};
+static const u32 page_write_regs_e2[] = {328476};
+static const struct reg_addr page_read_regs_e2[] = {
+       {0x58000, 4608, DUMP_CHIP_E2, 0x30}
+};
+
+#define PAGE_MODE_VALUES_E3 2
+#define PAGE_READ_REGS_E3 1
+#define PAGE_WRITE_REGS_E3 1
+static const u32 page_vals_e3[] = {0, 128};
+static const u32 page_write_regs_e3[] = {328476};
+static const struct reg_addr page_read_regs_e3[] = {
+       {0x58000, 4608, DUMP_CHIP_E3A0 | DUMP_CHIP_E3B0, 0x30}
 };
 
 static const struct reg_addr reg_addrs[] = {
-       { 0x2000, 341, RI_ALL_ONLINE },
-       { 0x2800, 103, RI_ALL_ONLINE },
-       { 0x3000, 287, RI_ALL_ONLINE },
-       { 0x3800, 331, RI_ALL_ONLINE },
-       { 0x8800, 6, RI_ALL_ONLINE },
-       { 0x8818, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x9000, 147, RI_E2E3E3B0_ONLINE },
-       { 0x924c, 1, RI_E2_ONLINE },
-       { 0x9250, 16, RI_E2E3E3B0_ONLINE },
-       { 0x9400, 33, RI_E2E3E3B0_ONLINE },
-       { 0x9484, 5, RI_E3E3B0_ONLINE },
-       { 0xa000, 27, RI_ALL_ONLINE },
-       { 0xa06c, 1, RI_E1E1H_ONLINE },
-       { 0xa070, 71, RI_ALL_ONLINE },
-       { 0xa18c, 4, RI_E1E1H_ONLINE },
-       { 0xa19c, 62, RI_ALL_ONLINE },
-       { 0xa294, 2, RI_E1E1H_ONLINE },
-       { 0xa29c, 2, RI_ALL_ONLINE },
-       { 0xa2a4, 2, RI_E1E1HE2_ONLINE },
-       { 0xa2ac, 52, RI_ALL_ONLINE },
-       { 0xa39c, 7, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa3b8, 2, RI_E3E3B0_ONLINE },
-       { 0xa3c0, 3, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa3d0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa3d8, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa3e0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa3e8, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa3f0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa3f8, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa400, 40, RI_ALL_ONLINE },
-       { 0xa4a0, 1, RI_E1E1HE2_ONLINE },
-       { 0xa4a4, 2, RI_ALL_ONLINE },
-       { 0xa4ac, 2, RI_E1E1H_ONLINE },
-       { 0xa4b4, 1, RI_E1E1HE2_ONLINE },
-       { 0xa4b8, 2, RI_E1E1H_ONLINE },
-       { 0xa4c0, 3, RI_ALL_ONLINE },
-       { 0xa4cc, 5, RI_E1E1H_ONLINE },
-       { 0xa4e0, 3, RI_ALL_ONLINE },
-       { 0xa4fc, 2, RI_ALL_ONLINE },
-       { 0xa504, 1, RI_E1E1H_ONLINE },
-       { 0xa508, 3, RI_ALL_ONLINE },
-       { 0xa518, 1, RI_ALL_ONLINE },
-       { 0xa520, 1, RI_ALL_ONLINE },
-       { 0xa528, 1, RI_ALL_ONLINE },
-       { 0xa530, 1, RI_ALL_ONLINE },
-       { 0xa538, 1, RI_ALL_ONLINE },
-       { 0xa540, 1, RI_ALL_ONLINE },
-       { 0xa548, 1, RI_E1E1H_ONLINE },
-       { 0xa550, 1, RI_E1E1H_ONLINE },
-       { 0xa558, 1, RI_E1E1H_ONLINE },
-       { 0xa560, 1, RI_E1E1H_ONLINE },
-       { 0xa568, 1, RI_E1E1H_ONLINE },
-       { 0xa570, 1, RI_ALL_ONLINE },
-       { 0xa580, 1, RI_ALL_ONLINE },
-       { 0xa590, 1, RI_ALL_ONLINE },
-       { 0xa5a0, 1, RI_E1E1HE2_ONLINE },
-       { 0xa5c0, 1, RI_ALL_ONLINE },
-       { 0xa5e0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa5e8, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa5f0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa5f8, 1, RI_E1HE2_ONLINE },
-       { 0xa5fc, 9, RI_E1HE2E3E3B0_ONLINE },
-       { 0xa620, 6, RI_E2E3E3B0_ONLINE },
-       { 0xa638, 20, RI_E2_ONLINE },
-       { 0xa688, 42, RI_E2E3E3B0_ONLINE },
-       { 0xa730, 1, RI_E2_ONLINE },
-       { 0xa734, 2, RI_E2E3E3B0_ONLINE },
-       { 0xa73c, 4, RI_E2_ONLINE },
-       { 0xa74c, 5, RI_E2E3E3B0_ONLINE },
-       { 0xa760, 5, RI_E2_ONLINE },
-       { 0xa774, 7, RI_E2E3E3B0_ONLINE },
-       { 0xa790, 15, RI_E2_ONLINE },
-       { 0xa7cc, 4, RI_E2E3E3B0_ONLINE },
-       { 0xa7e0, 6, RI_E3E3B0_ONLINE },
-       { 0xa800, 18, RI_E2_ONLINE },
-       { 0xa848, 33, RI_E2E3E3B0_ONLINE },
-       { 0xa8cc, 2, RI_E3E3B0_ONLINE },
-       { 0xa8d4, 4, RI_E2E3E3B0_ONLINE },
-       { 0xa8e4, 1, RI_E3E3B0_ONLINE },
-       { 0xa8e8, 1, RI_E2E3E3B0_ONLINE },
-       { 0xa8f0, 1, RI_E2E3E3B0_ONLINE },
-       { 0xa8f8, 30, RI_E3E3B0_ONLINE },
-       { 0xa974, 73, RI_E3E3B0_ONLINE },
-       { 0xac30, 1, RI_E3E3B0_ONLINE },
-       { 0xac40, 1, RI_E3E3B0_ONLINE },
-       { 0xac50, 1, RI_E3E3B0_ONLINE },
-       { 0xac60, 1, RI_E3B0_ONLINE },
-       { 0x10000, 9, RI_ALL_ONLINE },
-       { 0x10024, 1, RI_E1E1HE2_ONLINE },
-       { 0x10028, 5, RI_ALL_ONLINE },
-       { 0x1003c, 6, RI_E1E1HE2_ONLINE },
-       { 0x10054, 20, RI_ALL_ONLINE },
-       { 0x100a4, 4, RI_E1E1HE2_ONLINE },
-       { 0x100b4, 11, RI_ALL_ONLINE },
-       { 0x100e0, 4, RI_E1E1HE2_ONLINE },
-       { 0x100f0, 8, RI_ALL_ONLINE },
-       { 0x10110, 6, RI_E1E1HE2_ONLINE },
-       { 0x10128, 110, RI_ALL_ONLINE },
-       { 0x102e0, 4, RI_E1E1HE2_ONLINE },
-       { 0x102f0, 18, RI_ALL_ONLINE },
-       { 0x10338, 20, RI_E1E1HE2_ONLINE },
-       { 0x10388, 10, RI_ALL_ONLINE },
-       { 0x10400, 6, RI_E1E1HE2_ONLINE },
-       { 0x10418, 6, RI_ALL_ONLINE },
-       { 0x10430, 10, RI_E1E1HE2_ONLINE },
-       { 0x10458, 22, RI_ALL_ONLINE },
-       { 0x104b0, 12, RI_E1E1HE2_ONLINE },
-       { 0x104e0, 1, RI_ALL_ONLINE },
-       { 0x104e8, 2, RI_ALL_ONLINE },
-       { 0x104f4, 2, RI_ALL_ONLINE },
-       { 0x10500, 146, RI_ALL_ONLINE },
-       { 0x10750, 2, RI_E1E1HE2_ONLINE },
-       { 0x10760, 2, RI_E1E1HE2_ONLINE },
-       { 0x10770, 2, RI_E1E1HE2_ONLINE },
-       { 0x10780, 2, RI_E1E1HE2_ONLINE },
-       { 0x10790, 2, RI_ALL_ONLINE },
-       { 0x107a0, 2, RI_E1E1HE2_ONLINE },
-       { 0x107b0, 2, RI_E1E1HE2_ONLINE },
-       { 0x107c0, 2, RI_E1E1HE2_ONLINE },
-       { 0x107d0, 2, RI_E1E1HE2_ONLINE },
-       { 0x107e0, 2, RI_ALL_ONLINE },
-       { 0x10880, 2, RI_ALL_ONLINE },
-       { 0x10900, 2, RI_ALL_ONLINE },
-       { 0x16000, 1, RI_E1HE2_ONLINE },
-       { 0x16004, 25, RI_E1HE2E3E3B0_ONLINE },
-       { 0x16070, 8, RI_E1HE2E3E3B0_ONLINE },
-       { 0x16090, 4, RI_E1HE2E3_ONLINE },
-       { 0x160a0, 6, RI_E1HE2E3E3B0_ONLINE },
-       { 0x160c0, 7, RI_E1HE2E3E3B0_ONLINE },
-       { 0x160dc, 2, RI_E1HE2_ONLINE },
-       { 0x160e4, 10, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1610c, 2, RI_E1HE2_ONLINE },
-       { 0x16114, 6, RI_E1HE2E3E3B0_ONLINE },
-       { 0x16140, 48, RI_E1HE2E3E3B0_ONLINE },
-       { 0x16204, 5, RI_E1HE2E3E3B0_ONLINE },
-       { 0x18000, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x18008, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x18010, 35, RI_E2E3E3B0_ONLINE },
-       { 0x180a4, 2, RI_E2E3E3B0_ONLINE },
-       { 0x180c0, 9, RI_E2E3E3B0_ONLINE },
-       { 0x180e4, 1, RI_E2E3_ONLINE },
-       { 0x180e8, 2, RI_E2E3E3B0_ONLINE },
-       { 0x180f0, 1, RI_E2E3_ONLINE },
-       { 0x180f4, 79, RI_E2E3E3B0_ONLINE },
-       { 0x18230, 1, RI_E2E3_ONLINE },
-       { 0x18234, 2, RI_E2E3E3B0_ONLINE },
-       { 0x1823c, 1, RI_E2E3_ONLINE },
-       { 0x18240, 13, RI_E2E3E3B0_ONLINE },
-       { 0x18274, 1, RI_E2_ONLINE },
-       { 0x18278, 81, RI_E2E3E3B0_ONLINE },
-       { 0x18440, 63, RI_E2E3E3B0_ONLINE },
-       { 0x18570, 42, RI_E3E3B0_ONLINE },
-       { 0x18618, 25, RI_E3B0_ONLINE },
-       { 0x18680, 44, RI_E3B0_ONLINE },
-       { 0x18748, 12, RI_E3B0_ONLINE },
-       { 0x18788, 1, RI_E3B0_ONLINE },
-       { 0x1879c, 6, RI_E3B0_ONLINE },
-       { 0x187c4, 51, RI_E3B0_ONLINE },
-       { 0x18a00, 48, RI_E3B0_ONLINE },
-       { 0x20000, 24, RI_ALL_ONLINE },
-       { 0x20060, 8, RI_ALL_ONLINE },
-       { 0x20080, 94, RI_ALL_ONLINE },
-       { 0x201f8, 1, RI_E1E1H_ONLINE },
-       { 0x201fc, 1, RI_ALL_ONLINE },
-       { 0x20200, 1, RI_E1E1H_ONLINE },
-       { 0x20204, 1, RI_ALL_ONLINE },
-       { 0x20208, 1, RI_E1E1H_ONLINE },
-       { 0x2020c, 39, RI_ALL_ONLINE },
-       { 0x202c8, 1, RI_E2E3E3B0_ONLINE },
-       { 0x202d8, 4, RI_E2E3E3B0_ONLINE },
-       { 0x202f0, 1, RI_E3B0_ONLINE },
-       { 0x20400, 2, RI_ALL_ONLINE },
-       { 0x2040c, 8, RI_ALL_ONLINE },
-       { 0x2042c, 18, RI_E1HE2E3E3B0_ONLINE },
-       { 0x20480, 1, RI_ALL_ONLINE },
-       { 0x20500, 1, RI_ALL_ONLINE },
-       { 0x20600, 1, RI_ALL_ONLINE },
-       { 0x28000, 1, RI_ALL_ONLINE },
-       { 0x28004, 8191, RI_ALL_OFFLINE },
-       { 0x30000, 1, RI_ALL_ONLINE },
-       { 0x30004, 16383, RI_ALL_OFFLINE },
-       { 0x40000, 98, RI_ALL_ONLINE },
-       { 0x401a8, 8, RI_E1HE2E3E3B0_ONLINE },
-       { 0x401c8, 1, RI_E1H_ONLINE },
-       { 0x401cc, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x401d4, 2, RI_E2E3E3B0_ONLINE },
-       { 0x40200, 4, RI_ALL_ONLINE },
-       { 0x40220, 6, RI_E2E3E3B0_ONLINE },
-       { 0x40238, 8, RI_E2E3_ONLINE },
-       { 0x40258, 4, RI_E2E3E3B0_ONLINE },
-       { 0x40268, 2, RI_E3E3B0_ONLINE },
-       { 0x40270, 17, RI_E3B0_ONLINE },
-       { 0x40400, 43, RI_ALL_ONLINE },
-       { 0x404cc, 3, RI_E1HE2E3E3B0_ONLINE },
-       { 0x404e0, 1, RI_E2E3E3B0_ONLINE },
-       { 0x40500, 2, RI_ALL_ONLINE },
-       { 0x40510, 2, RI_ALL_ONLINE },
-       { 0x40520, 2, RI_ALL_ONLINE },
-       { 0x40530, 2, RI_ALL_ONLINE },
-       { 0x40540, 2, RI_ALL_ONLINE },
-       { 0x40550, 10, RI_E2E3E3B0_ONLINE },
-       { 0x40610, 2, RI_E2E3E3B0_ONLINE },
-       { 0x42000, 164, RI_ALL_ONLINE },
-       { 0x422c0, 4, RI_E2E3E3B0_ONLINE },
-       { 0x422d4, 5, RI_E1HE2E3E3B0_ONLINE },
-       { 0x422e8, 1, RI_E2E3E3B0_ONLINE },
-       { 0x42400, 49, RI_ALL_ONLINE },
-       { 0x424c8, 38, RI_ALL_ONLINE },
-       { 0x42568, 2, RI_ALL_ONLINE },
-       { 0x42640, 5, RI_E2E3E3B0_ONLINE },
-       { 0x42800, 1, RI_ALL_ONLINE },
-       { 0x50000, 1, RI_ALL_ONLINE },
-       { 0x50004, 19, RI_ALL_ONLINE },
-       { 0x50050, 8, RI_ALL_ONLINE },
-       { 0x50070, 88, RI_ALL_ONLINE },
-       { 0x501f0, 4, RI_E1HE2E3E3B0_ONLINE },
-       { 0x50200, 2, RI_ALL_ONLINE },
-       { 0x5020c, 7, RI_ALL_ONLINE },
-       { 0x50228, 6, RI_E1HE2E3E3B0_ONLINE },
-       { 0x50240, 1, RI_ALL_ONLINE },
-       { 0x50280, 1, RI_ALL_ONLINE },
-       { 0x50300, 1, RI_E2E3E3B0_ONLINE },
-       { 0x5030c, 1, RI_E2E3E3B0_ONLINE },
-       { 0x50318, 1, RI_E2E3E3B0_ONLINE },
-       { 0x5031c, 1, RI_E2E3E3B0_ONLINE },
-       { 0x50320, 2, RI_E2E3E3B0_ONLINE },
-       { 0x50330, 1, RI_E3B0_ONLINE },
-       { 0x52000, 1, RI_ALL_ONLINE },
-       { 0x54000, 1, RI_ALL_ONLINE },
-       { 0x54004, 3327, RI_ALL_OFFLINE },
-       { 0x58000, 1, RI_ALL_ONLINE },
-       { 0x58004, 8191, RI_E1E1H_OFFLINE },
-       { 0x60000, 26, RI_ALL_ONLINE },
-       { 0x60068, 8, RI_E1E1H_ONLINE },
-       { 0x60088, 12, RI_ALL_ONLINE },
-       { 0x600b8, 9, RI_E1E1H_ONLINE },
-       { 0x600dc, 1, RI_ALL_ONLINE },
-       { 0x600e0, 5, RI_E1E1H_ONLINE },
-       { 0x600f4, 1, RI_E1E1HE2_ONLINE },
-       { 0x600f8, 1, RI_E1E1H_ONLINE },
-       { 0x600fc, 8, RI_ALL_ONLINE },
-       { 0x6013c, 24, RI_E1H_ONLINE },
-       { 0x6019c, 2, RI_E2E3E3B0_ONLINE },
-       { 0x601ac, 18, RI_E2E3E3B0_ONLINE },
-       { 0x60200, 1, RI_ALL_ONLINE },
-       { 0x60204, 2, RI_ALL_OFFLINE },
-       { 0x60210, 13, RI_E2E3E3B0_ONLINE },
-       { 0x60244, 16, RI_E3B0_ONLINE },
-       { 0x61000, 1, RI_ALL_ONLINE },
-       { 0x61004, 511, RI_ALL_OFFLINE },
-       { 0x61800, 512, RI_E3E3B0_OFFLINE },
-       { 0x70000, 8, RI_ALL_ONLINE },
-       { 0x70020, 8184, RI_ALL_OFFLINE },
-       { 0x78000, 8192, RI_E3E3B0_OFFLINE },
-       { 0x85000, 3, RI_ALL_OFFLINE },
-       { 0x8501c, 7, RI_ALL_OFFLINE },
-       { 0x85048, 1, RI_ALL_OFFLINE },
-       { 0x85200, 32, RI_ALL_OFFLINE },
-       { 0xb0000, 16384, RI_E1H_OFFLINE },
-       { 0xc1000, 7, RI_ALL_ONLINE },
-       { 0xc103c, 2, RI_E2E3E3B0_ONLINE },
-       { 0xc1800, 2, RI_ALL_ONLINE },
-       { 0xc2000, 164, RI_ALL_ONLINE },
-       { 0xc22c0, 5, RI_E2E3E3B0_ONLINE },
-       { 0xc22d8, 4, RI_E2E3E3B0_ONLINE },
-       { 0xc2400, 49, RI_ALL_ONLINE },
-       { 0xc24c8, 38, RI_ALL_ONLINE },
-       { 0xc2568, 2, RI_ALL_ONLINE },
-       { 0xc2600, 1, RI_ALL_ONLINE },
-       { 0xc4000, 165, RI_ALL_ONLINE },
-       { 0xc42d8, 2, RI_E2E3E3B0_ONLINE },
-       { 0xc42e0, 7, RI_E1HE2E3E3B0_ONLINE },
-       { 0xc42fc, 1, RI_E2E3E3B0_ONLINE },
-       { 0xc4400, 51, RI_ALL_ONLINE },
-       { 0xc44d0, 38, RI_ALL_ONLINE },
-       { 0xc4570, 2, RI_ALL_ONLINE },
-       { 0xc4578, 5, RI_E2E3E3B0_ONLINE },
-       { 0xc4600, 1, RI_ALL_ONLINE },
-       { 0xd0000, 19, RI_ALL_ONLINE },
-       { 0xd004c, 8, RI_ALL_ONLINE },
-       { 0xd006c, 91, RI_ALL_ONLINE },
-       { 0xd01fc, 1, RI_E2E3E3B0_ONLINE },
-       { 0xd0200, 2, RI_ALL_ONLINE },
-       { 0xd020c, 7, RI_ALL_ONLINE },
-       { 0xd0228, 18, RI_E1HE2E3E3B0_ONLINE },
-       { 0xd0280, 1, RI_ALL_ONLINE },
-       { 0xd0300, 1, RI_ALL_ONLINE },
-       { 0xd0400, 1, RI_ALL_ONLINE },
-       { 0xd0818, 1, RI_E3B0_ONLINE },
-       { 0xd4000, 1, RI_ALL_ONLINE },
-       { 0xd4004, 2559, RI_ALL_OFFLINE },
-       { 0xd8000, 1, RI_ALL_ONLINE },
-       { 0xd8004, 8191, RI_ALL_OFFLINE },
-       { 0xe0000, 21, RI_ALL_ONLINE },
-       { 0xe0054, 8, RI_ALL_ONLINE },
-       { 0xe0074, 49, RI_ALL_ONLINE },
-       { 0xe0138, 1, RI_E1E1H_ONLINE },
-       { 0xe013c, 35, RI_ALL_ONLINE },
-       { 0xe01f4, 1, RI_E2_ONLINE },
-       { 0xe01f8, 1, RI_E2E3E3B0_ONLINE },
-       { 0xe0200, 2, RI_ALL_ONLINE },
-       { 0xe020c, 8, RI_ALL_ONLINE },
-       { 0xe022c, 18, RI_E1HE2E3E3B0_ONLINE },
-       { 0xe0280, 1, RI_ALL_ONLINE },
-       { 0xe0300, 1, RI_ALL_ONLINE },
-       { 0xe0400, 1, RI_E3B0_ONLINE },
-       { 0xe1000, 1, RI_ALL_ONLINE },
-       { 0xe2000, 1, RI_ALL_ONLINE },
-       { 0xe2004, 2047, RI_ALL_OFFLINE },
-       { 0xf0000, 1, RI_ALL_ONLINE },
-       { 0xf0004, 16383, RI_ALL_OFFLINE },
-       { 0x101000, 12, RI_ALL_ONLINE },
-       { 0x101050, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x101054, 3, RI_E2E3E3B0_ONLINE },
-       { 0x101100, 1, RI_ALL_ONLINE },
-       { 0x101800, 8, RI_ALL_ONLINE },
-       { 0x102000, 18, RI_ALL_ONLINE },
-       { 0x102068, 6, RI_E2E3E3B0_ONLINE },
-       { 0x102080, 17, RI_ALL_ONLINE },
-       { 0x1020c8, 8, RI_E1H_ONLINE },
-       { 0x1020e8, 9, RI_E2E3E3B0_ONLINE },
-       { 0x102400, 1, RI_ALL_ONLINE },
-       { 0x103000, 26, RI_ALL_ONLINE },
-       { 0x103098, 5, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1030ac, 2, RI_E2E3E3B0_ONLINE },
-       { 0x1030b4, 1, RI_E2_ONLINE },
-       { 0x1030b8, 7, RI_E2E3E3B0_ONLINE },
-       { 0x1030d8, 8, RI_E2E3E3B0_ONLINE },
-       { 0x103400, 1, RI_E2E3E3B0_ONLINE },
-       { 0x103404, 135, RI_E2E3E3B0_OFFLINE },
-       { 0x103800, 8, RI_ALL_ONLINE },
-       { 0x104000, 63, RI_ALL_ONLINE },
-       { 0x10411c, 16, RI_E2E3E3B0_ONLINE },
-       { 0x104200, 17, RI_ALL_ONLINE },
-       { 0x104400, 64, RI_ALL_ONLINE },
-       { 0x104500, 192, RI_ALL_OFFLINE },
-       { 0x104800, 64, RI_ALL_ONLINE },
-       { 0x104900, 192, RI_ALL_OFFLINE },
-       { 0x105000, 256, RI_ALL_ONLINE },
-       { 0x105400, 768, RI_ALL_OFFLINE },
-       { 0x107000, 7, RI_E2E3E3B0_ONLINE },
-       { 0x10701c, 1, RI_E3E3B0_ONLINE },
-       { 0x108000, 33, RI_E1E1H_ONLINE },
-       { 0x1080ac, 5, RI_E1H_ONLINE },
-       { 0x108100, 5, RI_E1E1H_ONLINE },
-       { 0x108120, 5, RI_E1E1H_ONLINE },
-       { 0x108200, 74, RI_E1E1H_ONLINE },
-       { 0x108400, 74, RI_E1E1H_ONLINE },
-       { 0x108800, 152, RI_E1E1H_ONLINE },
-       { 0x110000, 111, RI_E2E3E3B0_ONLINE },
-       { 0x1101dc, 1, RI_E3E3B0_ONLINE },
-       { 0x110200, 4, RI_E2E3E3B0_ONLINE },
-       { 0x120000, 2, RI_ALL_ONLINE },
-       { 0x120008, 4, RI_ALL_ONLINE },
-       { 0x120018, 3, RI_ALL_ONLINE },
-       { 0x120024, 4, RI_ALL_ONLINE },
-       { 0x120034, 3, RI_ALL_ONLINE },
-       { 0x120040, 4, RI_ALL_ONLINE },
-       { 0x120050, 3, RI_ALL_ONLINE },
-       { 0x12005c, 4, RI_ALL_ONLINE },
-       { 0x12006c, 3, RI_ALL_ONLINE },
-       { 0x120078, 4, RI_ALL_ONLINE },
-       { 0x120088, 3, RI_ALL_ONLINE },
-       { 0x120094, 4, RI_ALL_ONLINE },
-       { 0x1200a4, 3, RI_ALL_ONLINE },
-       { 0x1200b0, 4, RI_ALL_ONLINE },
-       { 0x1200c0, 3, RI_ALL_ONLINE },
-       { 0x1200cc, 4, RI_ALL_ONLINE },
-       { 0x1200dc, 3, RI_ALL_ONLINE },
-       { 0x1200e8, 4, RI_ALL_ONLINE },
-       { 0x1200f8, 3, RI_ALL_ONLINE },
-       { 0x120104, 4, RI_ALL_ONLINE },
-       { 0x120114, 1, RI_ALL_ONLINE },
-       { 0x120118, 22, RI_ALL_ONLINE },
-       { 0x120170, 2, RI_E1E1H_ONLINE },
-       { 0x120178, 243, RI_ALL_ONLINE },
-       { 0x120544, 4, RI_E1E1H_ONLINE },
-       { 0x120554, 6, RI_ALL_ONLINE },
-       { 0x12059c, 6, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1205b4, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1205b8, 15, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1205f4, 1, RI_E1HE2_ONLINE },
-       { 0x1205f8, 4, RI_E2E3E3B0_ONLINE },
-       { 0x120618, 1, RI_E2E3E3B0_ONLINE },
-       { 0x12061c, 20, RI_E1HE2E3E3B0_ONLINE },
-       { 0x12066c, 11, RI_E1HE2E3E3B0_ONLINE },
-       { 0x120698, 3, RI_E2E3E3B0_ONLINE },
-       { 0x1206a4, 1, RI_E2_ONLINE },
-       { 0x1206a8, 1, RI_E2E3E3B0_ONLINE },
-       { 0x1206b0, 75, RI_E2E3E3B0_ONLINE },
-       { 0x1207dc, 1, RI_E2_ONLINE },
-       { 0x1207fc, 1, RI_E2E3E3B0_ONLINE },
-       { 0x12080c, 65, RI_ALL_ONLINE },
-       { 0x120910, 7, RI_E2E3E3B0_ONLINE },
-       { 0x120930, 9, RI_E2E3E3B0_ONLINE },
-       { 0x12095c, 37, RI_E3E3B0_ONLINE },
-       { 0x120a00, 2, RI_E1E1HE2_ONLINE },
-       { 0x120b00, 1, RI_E3E3B0_ONLINE },
-       { 0x122000, 2, RI_ALL_ONLINE },
-       { 0x122008, 2046, RI_E1_OFFLINE },
-       { 0x128000, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x128008, 6142, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x130000, 35, RI_E2E3E3B0_ONLINE },
-       { 0x130100, 29, RI_E2E3E3B0_ONLINE },
-       { 0x130180, 1, RI_E2E3E3B0_ONLINE },
-       { 0x130200, 1, RI_E2E3E3B0_ONLINE },
-       { 0x130280, 1, RI_E2E3E3B0_ONLINE },
-       { 0x130300, 5, RI_E2E3E3B0_ONLINE },
-       { 0x130380, 1, RI_E2E3E3B0_ONLINE },
-       { 0x130400, 1, RI_E2E3E3B0_ONLINE },
-       { 0x130480, 5, RI_E2E3E3B0_ONLINE },
-       { 0x130800, 72, RI_E2E3E3B0_ONLINE },
-       { 0x131000, 136, RI_E2E3E3B0_ONLINE },
-       { 0x132000, 148, RI_E2E3E3B0_ONLINE },
-       { 0x134000, 544, RI_E2E3E3B0_ONLINE },
-       { 0x140000, 1, RI_ALL_ONLINE },
-       { 0x140004, 9, RI_E1E1HE2E3_ONLINE },
-       { 0x140028, 8, RI_ALL_ONLINE },
-       { 0x140048, 10, RI_E1E1HE2E3_ONLINE },
-       { 0x140070, 1, RI_ALL_ONLINE },
-       { 0x140074, 10, RI_E1E1HE2E3_ONLINE },
-       { 0x14009c, 1, RI_ALL_ONLINE },
-       { 0x1400a0, 5, RI_E1E1HE2E3_ONLINE },
-       { 0x1400b4, 7, RI_ALL_ONLINE },
-       { 0x1400d0, 10, RI_E1E1HE2E3_ONLINE },
-       { 0x1400f8, 2, RI_ALL_ONLINE },
-       { 0x140100, 5, RI_E1E1H_ONLINE },
-       { 0x140114, 5, RI_E1E1HE2E3_ONLINE },
-       { 0x140128, 7, RI_ALL_ONLINE },
-       { 0x140144, 9, RI_E1E1HE2E3_ONLINE },
-       { 0x140168, 8, RI_ALL_ONLINE },
-       { 0x140188, 3, RI_E1E1HE2E3_ONLINE },
-       { 0x140194, 13, RI_ALL_ONLINE },
-       { 0x140200, 6, RI_E1E1HE2E3_ONLINE },
-       { 0x140260, 4, RI_E2E3_ONLINE },
-       { 0x140280, 4, RI_E2E3_ONLINE },
-       { 0x1402e0, 2, RI_E2E3_ONLINE },
-       { 0x1402e8, 2, RI_E2E3E3B0_ONLINE },
-       { 0x1402f0, 9, RI_E2E3_ONLINE },
-       { 0x140314, 44, RI_E3B0_ONLINE },
-       { 0x144000, 4, RI_E1E1H_ONLINE },
-       { 0x148000, 4, RI_E1E1H_ONLINE },
-       { 0x14c000, 4, RI_E1E1H_ONLINE },
-       { 0x150000, 4, RI_E1E1H_ONLINE },
-       { 0x154000, 4, RI_E1E1H_ONLINE },
-       { 0x158000, 4, RI_E1E1H_ONLINE },
-       { 0x15c000, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x15c008, 5, RI_E1H_ONLINE },
-       { 0x15c020, 8, RI_E2E3E3B0_ONLINE },
-       { 0x15c040, 1, RI_E2E3_ONLINE },
-       { 0x15c044, 2, RI_E2E3E3B0_ONLINE },
-       { 0x15c04c, 8, RI_E2E3_ONLINE },
-       { 0x15c06c, 8, RI_E2E3E3B0_ONLINE },
-       { 0x15c090, 13, RI_E2E3E3B0_ONLINE },
-       { 0x15c0c8, 24, RI_E2E3E3B0_ONLINE },
-       { 0x15c128, 2, RI_E2E3_ONLINE },
-       { 0x15c130, 8, RI_E2E3E3B0_ONLINE },
-       { 0x15c150, 2, RI_E3E3B0_ONLINE },
-       { 0x15c158, 2, RI_E3_ONLINE },
-       { 0x15c160, 149, RI_E3B0_ONLINE },
-       { 0x161000, 7, RI_ALL_ONLINE },
-       { 0x16103c, 2, RI_E2E3E3B0_ONLINE },
-       { 0x161800, 2, RI_ALL_ONLINE },
-       { 0x162000, 54, RI_E3E3B0_ONLINE },
-       { 0x162200, 60, RI_E3E3B0_ONLINE },
-       { 0x162400, 54, RI_E3E3B0_ONLINE },
-       { 0x162600, 60, RI_E3E3B0_ONLINE },
-       { 0x162800, 54, RI_E3E3B0_ONLINE },
-       { 0x162a00, 60, RI_E3E3B0_ONLINE },
-       { 0x162c00, 54, RI_E3E3B0_ONLINE },
-       { 0x162e00, 60, RI_E3E3B0_ONLINE },
-       { 0x164000, 60, RI_ALL_ONLINE },
-       { 0x164110, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x164118, 15, RI_E2E3E3B0_ONLINE },
-       { 0x164200, 1, RI_ALL_ONLINE },
-       { 0x164208, 1, RI_ALL_ONLINE },
-       { 0x164210, 1, RI_ALL_ONLINE },
-       { 0x164218, 1, RI_ALL_ONLINE },
-       { 0x164220, 1, RI_ALL_ONLINE },
-       { 0x164228, 1, RI_ALL_ONLINE },
-       { 0x164230, 1, RI_ALL_ONLINE },
-       { 0x164238, 1, RI_ALL_ONLINE },
-       { 0x164240, 1, RI_ALL_ONLINE },
-       { 0x164248, 1, RI_ALL_ONLINE },
-       { 0x164250, 1, RI_ALL_ONLINE },
-       { 0x164258, 1, RI_ALL_ONLINE },
-       { 0x164260, 1, RI_ALL_ONLINE },
-       { 0x164270, 2, RI_ALL_ONLINE },
-       { 0x164280, 2, RI_ALL_ONLINE },
-       { 0x164800, 2, RI_ALL_ONLINE },
-       { 0x165000, 2, RI_ALL_ONLINE },
-       { 0x166000, 164, RI_ALL_ONLINE },
-       { 0x1662cc, 7, RI_E2E3E3B0_ONLINE },
-       { 0x166400, 49, RI_ALL_ONLINE },
-       { 0x1664c8, 38, RI_ALL_ONLINE },
-       { 0x166568, 2, RI_ALL_ONLINE },
-       { 0x166570, 5, RI_E2E3E3B0_ONLINE },
-       { 0x166800, 1, RI_ALL_ONLINE },
-       { 0x168000, 137, RI_ALL_ONLINE },
-       { 0x168224, 2, RI_E1E1H_ONLINE },
-       { 0x16822c, 29, RI_ALL_ONLINE },
-       { 0x1682a0, 12, RI_E1E1H_ONLINE },
-       { 0x1682d0, 12, RI_ALL_ONLINE },
-       { 0x168300, 2, RI_E1E1H_ONLINE },
-       { 0x168308, 68, RI_ALL_ONLINE },
-       { 0x168418, 2, RI_E1E1H_ONLINE },
-       { 0x168420, 6, RI_ALL_ONLINE },
-       { 0x168800, 19, RI_ALL_ONLINE },
-       { 0x168900, 1, RI_ALL_ONLINE },
-       { 0x168a00, 128, RI_ALL_ONLINE },
-       { 0x16a000, 1, RI_ALL_ONLINE },
-       { 0x16a004, 1535, RI_ALL_OFFLINE },
-       { 0x16c000, 1, RI_ALL_ONLINE },
-       { 0x16c004, 1535, RI_ALL_OFFLINE },
-       { 0x16e000, 16, RI_E1H_ONLINE },
-       { 0x16e040, 8, RI_E2E3E3B0_ONLINE },
-       { 0x16e100, 1, RI_E1H_ONLINE },
-       { 0x16e200, 2, RI_E1H_ONLINE },
-       { 0x16e400, 161, RI_E1H_ONLINE },
-       { 0x16e684, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x16e68c, 12, RI_E1H_ONLINE },
-       { 0x16e6bc, 4, RI_E1HE2E3E3B0_ONLINE },
-       { 0x16e6cc, 4, RI_E1H_ONLINE },
-       { 0x16e6e0, 2, RI_E2E3E3B0_ONLINE },
-       { 0x16e6e8, 5, RI_E2E3_ONLINE },
-       { 0x16e6fc, 5, RI_E2E3E3B0_ONLINE },
-       { 0x16e768, 17, RI_E2E3E3B0_ONLINE },
-       { 0x16e7ac, 12, RI_E3B0_ONLINE },
-       { 0x170000, 24, RI_ALL_ONLINE },
-       { 0x170060, 4, RI_E1E1H_ONLINE },
-       { 0x170070, 65, RI_ALL_ONLINE },
-       { 0x170194, 11, RI_E2E3E3B0_ONLINE },
-       { 0x1701c4, 1, RI_E2E3E3B0_ONLINE },
-       { 0x1701cc, 7, RI_E2E3E3B0_ONLINE },
-       { 0x1701e8, 1, RI_E3E3B0_ONLINE },
-       { 0x1701ec, 1, RI_E2E3E3B0_ONLINE },
-       { 0x1701f4, 1, RI_E2E3E3B0_ONLINE },
-       { 0x170200, 4, RI_ALL_ONLINE },
-       { 0x170214, 1, RI_ALL_ONLINE },
-       { 0x170218, 77, RI_E2E3E3B0_ONLINE },
-       { 0x170400, 64, RI_E2E3E3B0_ONLINE },
-       { 0x178000, 1, RI_ALL_ONLINE },
-       { 0x180000, 61, RI_ALL_ONLINE },
-       { 0x18013c, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x180200, 58, RI_ALL_ONLINE },
-       { 0x180340, 4, RI_ALL_ONLINE },
-       { 0x180380, 1, RI_E2E3E3B0_ONLINE },
-       { 0x180388, 1, RI_E2E3E3B0_ONLINE },
-       { 0x180390, 1, RI_E2E3E3B0_ONLINE },
-       { 0x180398, 1, RI_E2E3E3B0_ONLINE },
-       { 0x1803a0, 5, RI_E2E3E3B0_ONLINE },
-       { 0x1803b4, 2, RI_E3E3B0_ONLINE },
-       { 0x180404, 255, RI_E1E1H_OFFLINE },
-       { 0x181000, 4, RI_ALL_ONLINE },
-       { 0x181010, 1020, RI_ALL_OFFLINE },
-       { 0x182000, 4, RI_E3E3B0_ONLINE },
-       { 0x1a0000, 1, RI_ALL_ONLINE },
-       { 0x1a0004, 5631, RI_ALL_OFFLINE },
-       { 0x1a5800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x1a8000, 1, RI_ALL_ONLINE },
-       { 0x1a8004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x1b0000, 1, RI_ALL_ONLINE },
-       { 0x1b0004, 15, RI_E1H_OFFLINE },
-       { 0x1b0040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b0044, 239, RI_E1H_OFFLINE },
-       { 0x1b0400, 1, RI_ALL_ONLINE },
-       { 0x1b0404, 255, RI_E1H_OFFLINE },
-       { 0x1b0800, 1, RI_ALL_ONLINE },
-       { 0x1b0840, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b0c00, 1, RI_ALL_ONLINE },
-       { 0x1b1000, 1, RI_ALL_ONLINE },
-       { 0x1b1040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b1400, 1, RI_ALL_ONLINE },
-       { 0x1b1440, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b1480, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b14c0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b1800, 128, RI_ALL_OFFLINE },
-       { 0x1b1c00, 128, RI_ALL_OFFLINE },
-       { 0x1b2000, 1, RI_ALL_ONLINE },
-       { 0x1b2400, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b2404, 5631, RI_E2E3E3B0_OFFLINE },
-       { 0x1b8000, 1, RI_ALL_ONLINE },
-       { 0x1b8040, 1, RI_ALL_ONLINE },
-       { 0x1b8080, 1, RI_ALL_ONLINE },
-       { 0x1b80c0, 1, RI_ALL_ONLINE },
-       { 0x1b8100, 1, RI_ALL_ONLINE },
-       { 0x1b8140, 1, RI_ALL_ONLINE },
-       { 0x1b8180, 1, RI_ALL_ONLINE },
-       { 0x1b81c0, 1, RI_ALL_ONLINE },
-       { 0x1b8200, 1, RI_ALL_ONLINE },
-       { 0x1b8240, 1, RI_ALL_ONLINE },
-       { 0x1b8280, 1, RI_ALL_ONLINE },
-       { 0x1b82c0, 1, RI_ALL_ONLINE },
-       { 0x1b8300, 1, RI_ALL_ONLINE },
-       { 0x1b8340, 1, RI_ALL_ONLINE },
-       { 0x1b8380, 1, RI_ALL_ONLINE },
-       { 0x1b83c0, 1, RI_ALL_ONLINE },
-       { 0x1b8400, 1, RI_ALL_ONLINE },
-       { 0x1b8440, 1, RI_ALL_ONLINE },
-       { 0x1b8480, 1, RI_ALL_ONLINE },
-       { 0x1b84c0, 1, RI_ALL_ONLINE },
-       { 0x1b8500, 1, RI_ALL_ONLINE },
-       { 0x1b8540, 1, RI_ALL_ONLINE },
-       { 0x1b8580, 1, RI_ALL_ONLINE },
-       { 0x1b85c0, 19, RI_E2E3E3B0_ONLINE },
-       { 0x1b8800, 1, RI_ALL_ONLINE },
-       { 0x1b8840, 1, RI_ALL_ONLINE },
-       { 0x1b8880, 1, RI_ALL_ONLINE },
-       { 0x1b88c0, 1, RI_ALL_ONLINE },
-       { 0x1b8900, 1, RI_ALL_ONLINE },
-       { 0x1b8940, 1, RI_ALL_ONLINE },
-       { 0x1b8980, 1, RI_ALL_ONLINE },
-       { 0x1b89c0, 1, RI_ALL_ONLINE },
-       { 0x1b8a00, 1, RI_ALL_ONLINE },
-       { 0x1b8a40, 1, RI_ALL_ONLINE },
-       { 0x1b8a80, 1, RI_ALL_ONLINE },
-       { 0x1b8ac0, 1, RI_ALL_ONLINE },
-       { 0x1b8b00, 1, RI_ALL_ONLINE },
-       { 0x1b8b40, 1, RI_ALL_ONLINE },
-       { 0x1b8b80, 1, RI_ALL_ONLINE },
-       { 0x1b8bc0, 1, RI_ALL_ONLINE },
-       { 0x1b8c00, 1, RI_ALL_ONLINE },
-       { 0x1b8c40, 1, RI_ALL_ONLINE },
-       { 0x1b8c80, 1, RI_ALL_ONLINE },
-       { 0x1b8cc0, 1, RI_ALL_ONLINE },
-       { 0x1b8cc4, 1, RI_E2E3E3B0_ONLINE },
-       { 0x1b8d00, 1, RI_ALL_ONLINE },
-       { 0x1b8d40, 1, RI_ALL_ONLINE },
-       { 0x1b8d80, 1, RI_ALL_ONLINE },
-       { 0x1b8dc0, 1, RI_ALL_ONLINE },
-       { 0x1b8e00, 1, RI_ALL_ONLINE },
-       { 0x1b8e40, 1, RI_ALL_ONLINE },
-       { 0x1b8e80, 1, RI_ALL_ONLINE },
-       { 0x1b8e84, 1, RI_E2E3E3B0_ONLINE },
-       { 0x1b8ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b8f00, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b8f40, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b8f80, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b8fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x1b8fc4, 2, RI_E2E3E3B0_ONLINE },
-       { 0x1b8fd0, 6, RI_E2E3E3B0_ONLINE },
-       { 0x1b8fe8, 2, RI_E3E3B0_ONLINE },
-       { 0x1b9000, 1, RI_E2E3E3B0_ONLINE },
-       { 0x1b9040, 3, RI_E2E3E3B0_ONLINE },
-       { 0x1b905c, 1, RI_E3E3B0_ONLINE },
-       { 0x1b9064, 1, RI_E3B0_ONLINE },
-       { 0x1b9080, 10, RI_E3B0_ONLINE },
-       { 0x1b9400, 14, RI_E2E3E3B0_OFFLINE },
-       { 0x1b943c, 19, RI_E2E3E3B0_OFFLINE },
-       { 0x1b9490, 10, RI_E2E3E3B0_OFFLINE },
-       { 0x1c0000, 2, RI_ALL_ONLINE },
-       { 0x200000, 65, RI_ALL_ONLINE },
-       { 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x200200, 58, RI_ALL_ONLINE },
-       { 0x200340, 4, RI_ALL_ONLINE },
-       { 0x200380, 1, RI_E2E3E3B0_ONLINE },
-       { 0x200388, 1, RI_E2E3E3B0_ONLINE },
-       { 0x200390, 1, RI_E2E3E3B0_ONLINE },
-       { 0x200398, 1, RI_E2E3E3B0_ONLINE },
-       { 0x2003a0, 1, RI_E2E3E3B0_ONLINE },
-       { 0x2003a8, 2, RI_E2E3E3B0_ONLINE },
-       { 0x200404, 255, RI_E1E1H_OFFLINE },
-       { 0x202000, 4, RI_ALL_ONLINE },
-       { 0x202010, 2044, RI_ALL_OFFLINE },
-       { 0x204000, 4, RI_E3E3B0_ONLINE },
-       { 0x220000, 1, RI_ALL_ONLINE },
-       { 0x220004, 5631, RI_ALL_OFFLINE },
-       { 0x225800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x228000, 1, RI_ALL_ONLINE },
-       { 0x228004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x230000, 1, RI_ALL_ONLINE },
-       { 0x230004, 15, RI_E1H_OFFLINE },
-       { 0x230040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x230044, 239, RI_E1H_OFFLINE },
-       { 0x230400, 1, RI_ALL_ONLINE },
-       { 0x230404, 255, RI_E1H_OFFLINE },
-       { 0x230800, 1, RI_ALL_ONLINE },
-       { 0x230840, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x230c00, 1, RI_ALL_ONLINE },
-       { 0x231000, 1, RI_ALL_ONLINE },
-       { 0x231040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x231400, 1, RI_ALL_ONLINE },
-       { 0x231440, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x231480, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2314c0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x231800, 128, RI_ALL_OFFLINE },
-       { 0x231c00, 128, RI_ALL_OFFLINE },
-       { 0x232000, 1, RI_ALL_ONLINE },
-       { 0x232400, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x232404, 5631, RI_E2E3E3B0_OFFLINE },
-       { 0x238000, 1, RI_ALL_ONLINE },
-       { 0x238040, 1, RI_ALL_ONLINE },
-       { 0x238080, 1, RI_ALL_ONLINE },
-       { 0x2380c0, 1, RI_ALL_ONLINE },
-       { 0x238100, 1, RI_ALL_ONLINE },
-       { 0x238140, 1, RI_ALL_ONLINE },
-       { 0x238180, 1, RI_ALL_ONLINE },
-       { 0x2381c0, 1, RI_ALL_ONLINE },
-       { 0x238200, 1, RI_ALL_ONLINE },
-       { 0x238240, 1, RI_ALL_ONLINE },
-       { 0x238280, 1, RI_ALL_ONLINE },
-       { 0x2382c0, 1, RI_ALL_ONLINE },
-       { 0x238300, 1, RI_ALL_ONLINE },
-       { 0x238340, 1, RI_ALL_ONLINE },
-       { 0x238380, 1, RI_ALL_ONLINE },
-       { 0x2383c0, 1, RI_ALL_ONLINE },
-       { 0x238400, 1, RI_ALL_ONLINE },
-       { 0x238440, 1, RI_ALL_ONLINE },
-       { 0x238480, 1, RI_ALL_ONLINE },
-       { 0x2384c0, 1, RI_ALL_ONLINE },
-       { 0x238500, 1, RI_ALL_ONLINE },
-       { 0x238540, 1, RI_ALL_ONLINE },
-       { 0x238580, 1, RI_ALL_ONLINE },
-       { 0x2385c0, 19, RI_E2E3E3B0_ONLINE },
-       { 0x238800, 1, RI_ALL_ONLINE },
-       { 0x238840, 1, RI_ALL_ONLINE },
-       { 0x238880, 1, RI_ALL_ONLINE },
-       { 0x2388c0, 1, RI_ALL_ONLINE },
-       { 0x238900, 1, RI_ALL_ONLINE },
-       { 0x238940, 1, RI_ALL_ONLINE },
-       { 0x238980, 1, RI_ALL_ONLINE },
-       { 0x2389c0, 1, RI_ALL_ONLINE },
-       { 0x238a00, 1, RI_ALL_ONLINE },
-       { 0x238a40, 1, RI_ALL_ONLINE },
-       { 0x238a80, 1, RI_ALL_ONLINE },
-       { 0x238ac0, 1, RI_ALL_ONLINE },
-       { 0x238b00, 1, RI_ALL_ONLINE },
-       { 0x238b40, 1, RI_ALL_ONLINE },
-       { 0x238b80, 1, RI_ALL_ONLINE },
-       { 0x238bc0, 1, RI_ALL_ONLINE },
-       { 0x238c00, 1, RI_ALL_ONLINE },
-       { 0x238c40, 1, RI_ALL_ONLINE },
-       { 0x238c80, 1, RI_ALL_ONLINE },
-       { 0x238cc0, 1, RI_ALL_ONLINE },
-       { 0x238cc4, 1, RI_E2E3E3B0_ONLINE },
-       { 0x238d00, 1, RI_ALL_ONLINE },
-       { 0x238d40, 1, RI_ALL_ONLINE },
-       { 0x238d80, 1, RI_ALL_ONLINE },
-       { 0x238dc0, 1, RI_ALL_ONLINE },
-       { 0x238e00, 1, RI_ALL_ONLINE },
-       { 0x238e40, 1, RI_ALL_ONLINE },
-       { 0x238e80, 1, RI_ALL_ONLINE },
-       { 0x238e84, 1, RI_E2E3E3B0_ONLINE },
-       { 0x238ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x238f00, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x238f40, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x238f80, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x238fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x238fc4, 2, RI_E2E3E3B0_ONLINE },
-       { 0x238fd0, 6, RI_E2E3E3B0_ONLINE },
-       { 0x238fe8, 2, RI_E3E3B0_ONLINE },
-       { 0x239000, 1, RI_E2E3E3B0_ONLINE },
-       { 0x239040, 3, RI_E2E3E3B0_ONLINE },
-       { 0x23905c, 1, RI_E3E3B0_ONLINE },
-       { 0x239064, 1, RI_E3B0_ONLINE },
-       { 0x239080, 10, RI_E3B0_ONLINE },
-       { 0x240000, 2, RI_ALL_ONLINE },
-       { 0x280000, 65, RI_ALL_ONLINE },
-       { 0x28014c, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x280200, 58, RI_ALL_ONLINE },
-       { 0x280340, 4, RI_ALL_ONLINE },
-       { 0x280380, 1, RI_E2E3E3B0_ONLINE },
-       { 0x280388, 1, RI_E2E3E3B0_ONLINE },
-       { 0x280390, 1, RI_E2E3E3B0_ONLINE },
-       { 0x280398, 1, RI_E2E3E3B0_ONLINE },
-       { 0x2803a0, 1, RI_E2E3E3B0_ONLINE },
-       { 0x2803a8, 2, RI_E2E3E3B0_ONLINE },
-       { 0x280404, 255, RI_E1E1H_OFFLINE },
-       { 0x282000, 4, RI_ALL_ONLINE },
-       { 0x282010, 2044, RI_ALL_OFFLINE },
-       { 0x284000, 4, RI_E3E3B0_ONLINE },
-       { 0x2a0000, 1, RI_ALL_ONLINE },
-       { 0x2a0004, 5631, RI_ALL_OFFLINE },
-       { 0x2a5800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x2a8000, 1, RI_ALL_ONLINE },
-       { 0x2a8004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x2b0000, 1, RI_ALL_ONLINE },
-       { 0x2b0004, 15, RI_E1H_OFFLINE },
-       { 0x2b0040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b0044, 239, RI_E1H_OFFLINE },
-       { 0x2b0400, 1, RI_ALL_ONLINE },
-       { 0x2b0404, 255, RI_E1H_OFFLINE },
-       { 0x2b0800, 1, RI_ALL_ONLINE },
-       { 0x2b0840, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b0c00, 1, RI_ALL_ONLINE },
-       { 0x2b1000, 1, RI_ALL_ONLINE },
-       { 0x2b1040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b1400, 1, RI_ALL_ONLINE },
-       { 0x2b1440, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b1480, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b14c0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b1800, 128, RI_ALL_OFFLINE },
-       { 0x2b1c00, 128, RI_ALL_OFFLINE },
-       { 0x2b2000, 1, RI_ALL_ONLINE },
-       { 0x2b2400, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b2404, 5631, RI_E2E3E3B0_OFFLINE },
-       { 0x2b8000, 1, RI_ALL_ONLINE },
-       { 0x2b8040, 1, RI_ALL_ONLINE },
-       { 0x2b8080, 1, RI_ALL_ONLINE },
-       { 0x2b80c0, 1, RI_ALL_ONLINE },
-       { 0x2b8100, 1, RI_ALL_ONLINE },
-       { 0x2b8140, 1, RI_ALL_ONLINE },
-       { 0x2b8180, 1, RI_ALL_ONLINE },
-       { 0x2b81c0, 1, RI_ALL_ONLINE },
-       { 0x2b8200, 1, RI_ALL_ONLINE },
-       { 0x2b8240, 1, RI_ALL_ONLINE },
-       { 0x2b8280, 1, RI_ALL_ONLINE },
-       { 0x2b82c0, 1, RI_ALL_ONLINE },
-       { 0x2b8300, 1, RI_ALL_ONLINE },
-       { 0x2b8340, 1, RI_ALL_ONLINE },
-       { 0x2b8380, 1, RI_ALL_ONLINE },
-       { 0x2b83c0, 1, RI_ALL_ONLINE },
-       { 0x2b8400, 1, RI_ALL_ONLINE },
-       { 0x2b8440, 1, RI_ALL_ONLINE },
-       { 0x2b8480, 1, RI_ALL_ONLINE },
-       { 0x2b84c0, 1, RI_ALL_ONLINE },
-       { 0x2b8500, 1, RI_ALL_ONLINE },
-       { 0x2b8540, 1, RI_ALL_ONLINE },
-       { 0x2b8580, 1, RI_ALL_ONLINE },
-       { 0x2b85c0, 19, RI_E2E3E3B0_ONLINE },
-       { 0x2b8800, 1, RI_ALL_ONLINE },
-       { 0x2b8840, 1, RI_ALL_ONLINE },
-       { 0x2b8880, 1, RI_ALL_ONLINE },
-       { 0x2b88c0, 1, RI_ALL_ONLINE },
-       { 0x2b8900, 1, RI_ALL_ONLINE },
-       { 0x2b8940, 1, RI_ALL_ONLINE },
-       { 0x2b8980, 1, RI_ALL_ONLINE },
-       { 0x2b89c0, 1, RI_ALL_ONLINE },
-       { 0x2b8a00, 1, RI_ALL_ONLINE },
-       { 0x2b8a40, 1, RI_ALL_ONLINE },
-       { 0x2b8a80, 1, RI_ALL_ONLINE },
-       { 0x2b8ac0, 1, RI_ALL_ONLINE },
-       { 0x2b8b00, 1, RI_ALL_ONLINE },
-       { 0x2b8b40, 1, RI_ALL_ONLINE },
-       { 0x2b8b80, 1, RI_ALL_ONLINE },
-       { 0x2b8bc0, 1, RI_ALL_ONLINE },
-       { 0x2b8c00, 1, RI_ALL_ONLINE },
-       { 0x2b8c40, 1, RI_ALL_ONLINE },
-       { 0x2b8c80, 1, RI_ALL_ONLINE },
-       { 0x2b8cc0, 1, RI_ALL_ONLINE },
-       { 0x2b8cc4, 1, RI_E2E3E3B0_ONLINE },
-       { 0x2b8d00, 1, RI_ALL_ONLINE },
-       { 0x2b8d40, 1, RI_ALL_ONLINE },
-       { 0x2b8d80, 1, RI_ALL_ONLINE },
-       { 0x2b8dc0, 1, RI_ALL_ONLINE },
-       { 0x2b8e00, 1, RI_ALL_ONLINE },
-       { 0x2b8e40, 1, RI_ALL_ONLINE },
-       { 0x2b8e80, 1, RI_ALL_ONLINE },
-       { 0x2b8e84, 1, RI_E2E3E3B0_ONLINE },
-       { 0x2b8ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b8f00, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b8f40, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b8f80, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b8fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x2b8fc4, 2, RI_E2E3E3B0_ONLINE },
-       { 0x2b8fd0, 6, RI_E2E3E3B0_ONLINE },
-       { 0x2b8fe8, 2, RI_E3E3B0_ONLINE },
-       { 0x2b9000, 1, RI_E2E3E3B0_ONLINE },
-       { 0x2b9040, 3, RI_E2E3E3B0_ONLINE },
-       { 0x2b905c, 1, RI_E3E3B0_ONLINE },
-       { 0x2b9064, 1, RI_E3B0_ONLINE },
-       { 0x2b9080, 10, RI_E3B0_ONLINE },
-       { 0x2b9400, 14, RI_E2E3E3B0_ONLINE },
-       { 0x2b943c, 19, RI_E2E3E3B0_ONLINE },
-       { 0x2b9490, 10, RI_E2E3E3B0_ONLINE },
-       { 0x2c0000, 2, RI_ALL_ONLINE },
-       { 0x300000, 65, RI_ALL_ONLINE },
-       { 0x30014c, 2, RI_E1HE2E3E3B0_ONLINE },
-       { 0x300200, 58, RI_ALL_ONLINE },
-       { 0x300340, 4, RI_ALL_ONLINE },
-       { 0x300380, 1, RI_E2E3E3B0_ONLINE },
-       { 0x300388, 1, RI_E2E3E3B0_ONLINE },
-       { 0x300390, 1, RI_E2E3E3B0_ONLINE },
-       { 0x300398, 1, RI_E2E3E3B0_ONLINE },
-       { 0x3003a0, 1, RI_E2E3E3B0_ONLINE },
-       { 0x3003a8, 2, RI_E2E3E3B0_ONLINE },
-       { 0x300404, 255, RI_E1E1H_OFFLINE },
-       { 0x302000, 4, RI_ALL_ONLINE },
-       { 0x302010, 2044, RI_ALL_OFFLINE },
-       { 0x304000, 4, RI_E3E3B0_ONLINE },
-       { 0x320000, 1, RI_ALL_ONLINE },
-       { 0x320004, 5631, RI_ALL_OFFLINE },
-       { 0x325800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x328000, 1, RI_ALL_ONLINE },
-       { 0x328004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-       { 0x330000, 1, RI_ALL_ONLINE },
-       { 0x330004, 15, RI_E1H_OFFLINE },
-       { 0x330040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x330044, 239, RI_E1H_OFFLINE },
-       { 0x330400, 1, RI_ALL_ONLINE },
-       { 0x330404, 255, RI_E1H_OFFLINE },
-       { 0x330800, 1, RI_ALL_ONLINE },
-       { 0x330840, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x330c00, 1, RI_ALL_ONLINE },
-       { 0x331000, 1, RI_ALL_ONLINE },
-       { 0x331040, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x331400, 1, RI_ALL_ONLINE },
-       { 0x331440, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x331480, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x3314c0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x331800, 128, RI_ALL_OFFLINE },
-       { 0x331c00, 128, RI_ALL_OFFLINE },
-       { 0x332000, 1, RI_ALL_ONLINE },
-       { 0x332400, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x332404, 5631, RI_E2E3E3B0_OFFLINE },
-       { 0x338000, 1, RI_ALL_ONLINE },
-       { 0x338040, 1, RI_ALL_ONLINE },
-       { 0x338080, 1, RI_ALL_ONLINE },
-       { 0x3380c0, 1, RI_ALL_ONLINE },
-       { 0x338100, 1, RI_ALL_ONLINE },
-       { 0x338140, 1, RI_ALL_ONLINE },
-       { 0x338180, 1, RI_ALL_ONLINE },
-       { 0x3381c0, 1, RI_ALL_ONLINE },
-       { 0x338200, 1, RI_ALL_ONLINE },
-       { 0x338240, 1, RI_ALL_ONLINE },
-       { 0x338280, 1, RI_ALL_ONLINE },
-       { 0x3382c0, 1, RI_ALL_ONLINE },
-       { 0x338300, 1, RI_ALL_ONLINE },
-       { 0x338340, 1, RI_ALL_ONLINE },
-       { 0x338380, 1, RI_ALL_ONLINE },
-       { 0x3383c0, 1, RI_ALL_ONLINE },
-       { 0x338400, 1, RI_ALL_ONLINE },
-       { 0x338440, 1, RI_ALL_ONLINE },
-       { 0x338480, 1, RI_ALL_ONLINE },
-       { 0x3384c0, 1, RI_ALL_ONLINE },
-       { 0x338500, 1, RI_ALL_ONLINE },
-       { 0x338540, 1, RI_ALL_ONLINE },
-       { 0x338580, 1, RI_ALL_ONLINE },
-       { 0x3385c0, 19, RI_E2E3E3B0_ONLINE },
-       { 0x338800, 1, RI_ALL_ONLINE },
-       { 0x338840, 1, RI_ALL_ONLINE },
-       { 0x338880, 1, RI_ALL_ONLINE },
-       { 0x3388c0, 1, RI_ALL_ONLINE },
-       { 0x338900, 1, RI_ALL_ONLINE },
-       { 0x338940, 1, RI_ALL_ONLINE },
-       { 0x338980, 1, RI_ALL_ONLINE },
-       { 0x3389c0, 1, RI_ALL_ONLINE },
-       { 0x338a00, 1, RI_ALL_ONLINE },
-       { 0x338a40, 1, RI_ALL_ONLINE },
-       { 0x338a80, 1, RI_ALL_ONLINE },
-       { 0x338ac0, 1, RI_ALL_ONLINE },
-       { 0x338b00, 1, RI_ALL_ONLINE },
-       { 0x338b40, 1, RI_ALL_ONLINE },
-       { 0x338b80, 1, RI_ALL_ONLINE },
-       { 0x338bc0, 1, RI_ALL_ONLINE },
-       { 0x338c00, 1, RI_ALL_ONLINE },
-       { 0x338c40, 1, RI_ALL_ONLINE },
-       { 0x338c80, 1, RI_ALL_ONLINE },
-       { 0x338cc0, 1, RI_ALL_ONLINE },
-       { 0x338cc4, 1, RI_E2E3E3B0_ONLINE },
-       { 0x338d00, 1, RI_ALL_ONLINE },
-       { 0x338d40, 1, RI_ALL_ONLINE },
-       { 0x338d80, 1, RI_ALL_ONLINE },
-       { 0x338dc0, 1, RI_ALL_ONLINE },
-       { 0x338e00, 1, RI_ALL_ONLINE },
-       { 0x338e40, 1, RI_ALL_ONLINE },
-       { 0x338e80, 1, RI_ALL_ONLINE },
-       { 0x338e84, 1, RI_E2E3E3B0_ONLINE },
-       { 0x338ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x338f00, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x338f40, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x338f80, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x338fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-       { 0x338fc4, 2, RI_E2E3E3B0_ONLINE },
-       { 0x338fd0, 6, RI_E2E3E3B0_ONLINE },
-       { 0x338fe8, 2, RI_E3E3B0_ONLINE },
-       { 0x339000, 1, RI_E2E3E3B0_ONLINE },
-       { 0x339040, 3, RI_E2E3E3B0_ONLINE },
-       { 0x33905c, 1, RI_E3E3B0_ONLINE },
-       { 0x339064, 1, RI_E3B0_ONLINE },
-       { 0x339080, 10, RI_E3B0_ONLINE },
-       { 0x340000, 2, RI_ALL_ONLINE },
+       { 0x2000, 1, 0x1f, 0xfff},
+       { 0x2004, 1, 0x1f, 0x1fff},
+       { 0x2008, 25, 0x1f, 0xfff},
+       { 0x206c, 1, 0x1f, 0x1fff},
+       { 0x2070, 313, 0x1f, 0xfff},
+       { 0x2800, 103, 0x1f, 0xfff},
+       { 0x3000, 287, 0x1f, 0xfff},
+       { 0x3800, 331, 0x1f, 0xfff},
+       { 0x8800, 6, 0x1f, 0x924},
+       { 0x8818, 1, 0x1e, 0x924},
+       { 0x9000, 4, 0x1c, 0x924},
+       { 0x9010, 7, 0x1c, 0xfff},
+       { 0x902c, 1, 0x1c, 0x924},
+       { 0x9030, 1, 0x1c, 0xfff},
+       { 0x9034, 13, 0x1c, 0x924},
+       { 0x9068, 16, 0x1c, 0xfff},
+       { 0x90a8, 98, 0x1c, 0x924},
+       { 0x9230, 2, 0x1c, 0xfff},
+       { 0x9238, 3, 0x1c, 0x924},
+       { 0x9244, 1, 0x1c, 0xfff},
+       { 0x9248, 1, 0x1c, 0x924},
+       { 0x924c, 1, 0x4, 0x924},
+       { 0x9250, 16, 0x1c, 0x924},
+       { 0x92a8, 2, 0x1c, 0x1fff},
+       { 0x92b4, 1, 0x1c, 0x1fff},
+       { 0x9400, 33, 0x1c, 0x924},
+       { 0x9484, 5, 0x18, 0x924},
+       { 0xa000, 27, 0x1f, 0x924},
+       { 0xa06c, 1, 0x3, 0x924},
+       { 0xa070, 2, 0x1f, 0x924},
+       { 0xa078, 1, 0x1f, 0x1fff},
+       { 0xa07c, 31, 0x1f, 0x924},
+       { 0xa0f8, 1, 0x1f, 0x1fff},
+       { 0xa0fc, 3, 0x1f, 0x924},
+       { 0xa108, 1, 0x1f, 0x1fff},
+       { 0xa10c, 3, 0x1f, 0x924},
+       { 0xa118, 1, 0x1f, 0x1fff},
+       { 0xa11c, 28, 0x1f, 0x924},
+       { 0xa18c, 4, 0x3, 0x924},
+       { 0xa19c, 3, 0x1f, 0x924},
+       { 0xa1a8, 1, 0x1f, 0x1fff},
+       { 0xa1ac, 3, 0x1f, 0x924},
+       { 0xa1b8, 1, 0x1f, 0x1fff},
+       { 0xa1bc, 54, 0x1f, 0x924},
+       { 0xa294, 2, 0x3, 0x924},
+       { 0xa29c, 2, 0x1f, 0x924},
+       { 0xa2a4, 2, 0x7, 0x924},
+       { 0xa2ac, 2, 0x1f, 0x924},
+       { 0xa2b4, 1, 0x1f, 0x1fff},
+       { 0xa2b8, 49, 0x1f, 0x924},
+       { 0xa38c, 2, 0x1f, 0x1fff},
+       { 0xa398, 1, 0x1f, 0x1fff},
+       { 0xa39c, 7, 0x1e, 0x924},
+       { 0xa3b8, 2, 0x18, 0x924},
+       { 0xa3c0, 1, 0x1e, 0x924},
+       { 0xa3c4, 1, 0x1e, 0xfff},
+       { 0xa3c8, 1, 0x1e, 0x924},
+       { 0xa3d0, 1, 0x1e, 0x924},
+       { 0xa3d8, 1, 0x1e, 0x924},
+       { 0xa3e0, 1, 0x1e, 0x924},
+       { 0xa3e8, 1, 0x1e, 0x924},
+       { 0xa3f0, 1, 0x1e, 0x924},
+       { 0xa3f8, 1, 0x1e, 0x924},
+       { 0xa400, 1, 0x1f, 0x924},
+       { 0xa404, 1, 0x1f, 0xfff},
+       { 0xa408, 2, 0x1f, 0x1fff},
+       { 0xa410, 7, 0x1f, 0x924},
+       { 0xa42c, 12, 0x1f, 0xfff},
+       { 0xa45c, 1, 0x1f, 0x924},
+       { 0xa460, 1, 0x1f, 0x1924},
+       { 0xa464, 15, 0x1f, 0x924},
+       { 0xa4a0, 1, 0x7, 0x924},
+       { 0xa4a4, 2, 0x1f, 0x924},
+       { 0xa4ac, 2, 0x3, 0x924},
+       { 0xa4b4, 1, 0x7, 0x924},
+       { 0xa4b8, 2, 0x3, 0x924},
+       { 0xa4c0, 3, 0x1f, 0x924},
+       { 0xa4cc, 5, 0x3, 0x924},
+       { 0xa4e0, 3, 0x1f, 0x924},
+       { 0xa4fc, 2, 0x1f, 0x924},
+       { 0xa504, 1, 0x3, 0x924},
+       { 0xa508, 3, 0x1f, 0x924},
+       { 0xa518, 1, 0x1f, 0x924},
+       { 0xa520, 1, 0x1f, 0x924},
+       { 0xa528, 1, 0x1f, 0x924},
+       { 0xa530, 1, 0x1f, 0x924},
+       { 0xa538, 1, 0x1f, 0x924},
+       { 0xa540, 1, 0x1f, 0x924},
+       { 0xa548, 1, 0x3, 0x924},
+       { 0xa550, 1, 0x3, 0x924},
+       { 0xa558, 1, 0x3, 0x924},
+       { 0xa560, 1, 0x3, 0x924},
+       { 0xa568, 1, 0x3, 0x924},
+       { 0xa570, 1, 0x1f, 0x924},
+       { 0xa580, 1, 0x1f, 0x1fff},
+       { 0xa590, 1, 0x1f, 0x1fff},
+       { 0xa5a0, 1, 0x7, 0x924},
+       { 0xa5c0, 1, 0x1f, 0x924},
+       { 0xa5e0, 1, 0x1e, 0x924},
+       { 0xa5e8, 1, 0x1e, 0x924},
+       { 0xa5f0, 1, 0x1e, 0x924},
+       { 0xa5f8, 1, 0x6, 0x924},
+       { 0xa5fc, 1, 0x1e, 0x924},
+       { 0xa600, 5, 0x1e, 0xfff},
+       { 0xa614, 1, 0x1e, 0x924},
+       { 0xa618, 1, 0x1e, 0xfff},
+       { 0xa61c, 1, 0x1e, 0x924},
+       { 0xa620, 6, 0x1c, 0x924},
+       { 0xa638, 20, 0x4, 0x924},
+       { 0xa688, 35, 0x1c, 0x924},
+       { 0xa714, 1, 0x1c, 0xfff},
+       { 0xa718, 2, 0x1c, 0x924},
+       { 0xa720, 1, 0x1c, 0xfff},
+       { 0xa724, 3, 0x1c, 0x924},
+       { 0xa730, 1, 0x4, 0x924},
+       { 0xa734, 2, 0x1c, 0x924},
+       { 0xa73c, 4, 0x4, 0x924},
+       { 0xa74c, 1, 0x1c, 0x924},
+       { 0xa750, 1, 0x1c, 0xfff},
+       { 0xa754, 3, 0x1c, 0x924},
+       { 0xa760, 5, 0x4, 0x924},
+       { 0xa774, 7, 0x1c, 0x924},
+       { 0xa790, 15, 0x4, 0x924},
+       { 0xa7cc, 4, 0x1c, 0x924},
+       { 0xa7e0, 6, 0x18, 0x924},
+       { 0xa800, 18, 0x4, 0x924},
+       { 0xa848, 33, 0x1c, 0x924},
+       { 0xa8cc, 2, 0x18, 0x924},
+       { 0xa8d4, 4, 0x1c, 0x924},
+       { 0xa8e4, 1, 0x18, 0x924},
+       { 0xa8e8, 1, 0x1c, 0x924},
+       { 0xa8f0, 1, 0x1c, 0x924},
+       { 0xa8f8, 30, 0x18, 0x924},
+       { 0xa974, 73, 0x18, 0x924},
+       { 0xac30, 1, 0x18, 0x924},
+       { 0xac40, 1, 0x18, 0x924},
+       { 0xac50, 1, 0x18, 0x924},
+       { 0xac60, 1, 0x10, 0x924},
+       { 0x10000, 9, 0x1f, 0x924},
+       { 0x10024, 1, 0x7, 0x924},
+       { 0x10028, 5, 0x1f, 0x924},
+       { 0x1003c, 6, 0x7, 0x924},
+       { 0x10054, 20, 0x1f, 0x924},
+       { 0x100a4, 4, 0x7, 0x924},
+       { 0x100b4, 11, 0x1f, 0x924},
+       { 0x100e0, 4, 0x7, 0x924},
+       { 0x100f0, 8, 0x1f, 0x924},
+       { 0x10110, 6, 0x7, 0x924},
+       { 0x10128, 110, 0x1f, 0x924},
+       { 0x102e0, 4, 0x7, 0x924},
+       { 0x102f0, 18, 0x1f, 0x924},
+       { 0x10338, 20, 0x7, 0x924},
+       { 0x10388, 10, 0x1f, 0x924},
+       { 0x103d0, 2, 0x3, 0x1fff},
+       { 0x103dc, 1, 0x3, 0x1fff},
+       { 0x10400, 6, 0x7, 0x924},
+       { 0x10418, 1, 0x1f, 0xfff},
+       { 0x1041c, 1, 0x1f, 0x924},
+       { 0x10420, 1, 0x1f, 0xfff},
+       { 0x10424, 1, 0x1f, 0x924},
+       { 0x10428, 1, 0x1f, 0xfff},
+       { 0x1042c, 1, 0x1f, 0x924},
+       { 0x10430, 10, 0x7, 0x924},
+       { 0x10458, 2, 0x1f, 0x924},
+       { 0x10460, 1, 0x1f, 0xfff},
+       { 0x10464, 4, 0x1f, 0x924},
+       { 0x10474, 1, 0x1f, 0xfff},
+       { 0x10478, 14, 0x1f, 0x924},
+       { 0x104b0, 12, 0x7, 0x924},
+       { 0x104e0, 1, 0x1f, 0xfff},
+       { 0x104e8, 1, 0x1f, 0x924},
+       { 0x104ec, 1, 0x1f, 0xfff},
+       { 0x104f4, 1, 0x1f, 0x924},
+       { 0x104f8, 1, 0x1f, 0xfff},
+       { 0x10500, 2, 0x1f, 0x924},
+       { 0x10508, 1, 0x1f, 0xfff},
+       { 0x1050c, 9, 0x1f, 0x924},
+       { 0x10530, 1, 0x1f, 0xfff},
+       { 0x10534, 1, 0x1f, 0x924},
+       { 0x10538, 1, 0x1f, 0xfff},
+       { 0x1053c, 3, 0x1f, 0x924},
+       { 0x10548, 1, 0x1f, 0xfff},
+       { 0x1054c, 3, 0x1f, 0x924},
+       { 0x10558, 1, 0x1f, 0xfff},
+       { 0x1055c, 123, 0x1f, 0x924},
+       { 0x10750, 2, 0x7, 0x924},
+       { 0x10760, 2, 0x7, 0x924},
+       { 0x10770, 2, 0x7, 0x924},
+       { 0x10780, 2, 0x7, 0x924},
+       { 0x10790, 2, 0x1f, 0x924},
+       { 0x107a0, 2, 0x7, 0x924},
+       { 0x107b0, 2, 0x7, 0x924},
+       { 0x107c0, 2, 0x7, 0x924},
+       { 0x107d0, 2, 0x7, 0x924},
+       { 0x107e0, 2, 0x1f, 0x924},
+       { 0x10880, 2, 0x1f, 0x924},
+       { 0x10900, 2, 0x1f, 0x924},
+       { 0x16000, 1, 0x6, 0x924},
+       { 0x16004, 25, 0x1e, 0x924},
+       { 0x16070, 8, 0x1e, 0x924},
+       { 0x16090, 4, 0xe, 0x924},
+       { 0x160a0, 6, 0x1e, 0x924},
+       { 0x160c0, 7, 0x1e, 0x924},
+       { 0x160dc, 2, 0x6, 0x924},
+       { 0x160e4, 6, 0x1e, 0x924},
+       { 0x160fc, 4, 0x1e, 0x1fff},
+       { 0x1610c, 2, 0x6, 0x924},
+       { 0x16114, 6, 0x1e, 0x924},
+       { 0x16140, 48, 0x1e, 0x1fff},
+       { 0x16204, 5, 0x1e, 0x924},
+       { 0x18000, 1, 0x1e, 0x924},
+       { 0x18008, 1, 0x1e, 0x924},
+       { 0x18010, 35, 0x1c, 0x924},
+       { 0x180a4, 2, 0x1c, 0x924},
+       { 0x180c0, 9, 0x1c, 0x924},
+       { 0x180e4, 1, 0xc, 0x924},
+       { 0x180e8, 2, 0x1c, 0x924},
+       { 0x180f0, 1, 0xc, 0x924},
+       { 0x180f4, 79, 0x1c, 0x924},
+       { 0x18230, 1, 0xc, 0x924},
+       { 0x18234, 2, 0x1c, 0x924},
+       { 0x1823c, 1, 0xc, 0x924},
+       { 0x18240, 13, 0x1c, 0x924},
+       { 0x18274, 1, 0x4, 0x924},
+       { 0x18278, 12, 0x1c, 0x924},
+       { 0x182a8, 1, 0x1c, 0xfff},
+       { 0x182ac, 3, 0x1c, 0x924},
+       { 0x182b8, 1, 0x1c, 0xfff},
+       { 0x182bc, 19, 0x1c, 0x924},
+       { 0x18308, 1, 0x1c, 0xfff},
+       { 0x1830c, 3, 0x1c, 0x924},
+       { 0x18318, 1, 0x1c, 0xfff},
+       { 0x1831c, 7, 0x1c, 0x924},
+       { 0x18338, 1, 0x1c, 0xfff},
+       { 0x1833c, 3, 0x1c, 0x924},
+       { 0x18348, 1, 0x1c, 0xfff},
+       { 0x1834c, 28, 0x1c, 0x924},
+       { 0x183bc, 2, 0x1c, 0x1fff},
+       { 0x183c8, 3, 0x1c, 0x1fff},
+       { 0x183d8, 1, 0x1c, 0x1fff},
+       { 0x18440, 48, 0x1c, 0x1fff},
+       { 0x18500, 15, 0x1c, 0x924},
+       { 0x18570, 1, 0x18, 0xfff},
+       { 0x18574, 1, 0x18, 0x924},
+       { 0x18578, 1, 0x18, 0xfff},
+       { 0x1857c, 4, 0x18, 0x924},
+       { 0x1858c, 1, 0x18, 0xfff},
+       { 0x18590, 1, 0x18, 0x924},
+       { 0x18594, 1, 0x18, 0xfff},
+       { 0x18598, 32, 0x18, 0x924},
+       { 0x18618, 5, 0x10, 0x924},
+       { 0x1862c, 4, 0x10, 0xfff},
+       { 0x1863c, 16, 0x10, 0x924},
+       { 0x18680, 44, 0x10, 0x924},
+       { 0x18748, 12, 0x10, 0x924},
+       { 0x18788, 1, 0x10, 0x924},
+       { 0x1879c, 6, 0x10, 0x924},
+       { 0x187c4, 51, 0x10, 0x924},
+       { 0x18a00, 48, 0x10, 0x924},
+       { 0x20000, 24, 0x1f, 0x924},
+       { 0x20060, 8, 0x1f, 0x9e4},
+       { 0x20080, 94, 0x1f, 0x924},
+       { 0x201f8, 1, 0x3, 0x924},
+       { 0x201fc, 1, 0x1f, 0x924},
+       { 0x20200, 1, 0x3, 0x924},
+       { 0x20204, 1, 0x1f, 0x924},
+       { 0x20208, 1, 0x3, 0x924},
+       { 0x2020c, 4, 0x1f, 0x924},
+       { 0x2021c, 11, 0x1f, 0xfff},
+       { 0x20248, 24, 0x1f, 0x924},
+       { 0x202b8, 2, 0x1f, 0x1fff},
+       { 0x202c4, 1, 0x1f, 0x1fff},
+       { 0x202c8, 1, 0x1c, 0x924},
+       { 0x202d8, 4, 0x1c, 0x924},
+       { 0x202f0, 1, 0x10, 0x924},
+       { 0x20400, 1, 0x1f, 0x924},
+       { 0x20404, 1, 0x1f, 0xfff},
+       { 0x2040c, 2, 0x1f, 0xfff},
+       { 0x20414, 2, 0x1f, 0x924},
+       { 0x2041c, 2, 0x1f, 0xfff},
+       { 0x20424, 2, 0x1f, 0x924},
+       { 0x2042c, 18, 0x1e, 0x924},
+       { 0x20480, 1, 0x1f, 0x924},
+       { 0x20500, 1, 0x1f, 0x924},
+       { 0x20600, 1, 0x1f, 0x924},
+       { 0x28000, 1, 0x1f, 0x9e4},
+       { 0x28004, 255, 0x1f, 0x180},
+       { 0x28400, 1, 0x1f, 0x1c0},
+       { 0x28404, 255, 0x1f, 0x180},
+       { 0x28800, 1, 0x1f, 0x1c0},
+       { 0x28804, 255, 0x1f, 0x180},
+       { 0x28c00, 1, 0x1f, 0x1c0},
+       { 0x28c04, 255, 0x1f, 0x180},
+       { 0x29000, 1, 0x1f, 0x1c0},
+       { 0x29004, 255, 0x1f, 0x180},
+       { 0x29400, 1, 0x1f, 0x1c0},
+       { 0x29404, 255, 0x1f, 0x180},
+       { 0x29800, 1, 0x1f, 0x1c0},
+       { 0x29804, 255, 0x1f, 0x180},
+       { 0x29c00, 1, 0x1f, 0x1c0},
+       { 0x29c04, 255, 0x1f, 0x180},
+       { 0x2a000, 1, 0x1f, 0x1c0},
+       { 0x2a004, 255, 0x1f, 0x180},
+       { 0x2a400, 1, 0x1f, 0x1c0},
+       { 0x2a404, 255, 0x1f, 0x180},
+       { 0x2a800, 1, 0x1f, 0x1c0},
+       { 0x2a804, 255, 0x1f, 0x180},
+       { 0x2ac00, 1, 0x1f, 0x1c0},
+       { 0x2ac04, 255, 0x1f, 0x180},
+       { 0x2b000, 1, 0x1f, 0x1c0},
+       { 0x2b004, 255, 0x1f, 0x180},
+       { 0x2b400, 1, 0x1f, 0x1c0},
+       { 0x2b404, 255, 0x1f, 0x180},
+       { 0x2b800, 1, 0x1f, 0x1c0},
+       { 0x2b804, 255, 0x1f, 0x180},
+       { 0x2bc00, 1, 0x1f, 0x1c0},
+       { 0x2bc04, 255, 0x1f, 0x180},
+       { 0x2c000, 1, 0x1f, 0x1c0},
+       { 0x2c004, 255, 0x1f, 0x180},
+       { 0x2c400, 1, 0x1f, 0x1c0},
+       { 0x2c404, 255, 0x1f, 0x180},
+       { 0x2c800, 1, 0x1f, 0x1c0},
+       { 0x2c804, 255, 0x1f, 0x180},
+       { 0x2cc00, 1, 0x1f, 0x1c0},
+       { 0x2cc04, 255, 0x1f, 0x180},
+       { 0x2d000, 1, 0x1f, 0x1c0},
+       { 0x2d004, 255, 0x1f, 0x180},
+       { 0x2d400, 1, 0x1f, 0x1c0},
+       { 0x2d404, 255, 0x1f, 0x180},
+       { 0x2d800, 1, 0x1f, 0x1c0},
+       { 0x2d804, 255, 0x1f, 0x180},
+       { 0x2dc00, 1, 0x1f, 0x1c0},
+       { 0x2dc04, 255, 0x1f, 0x180},
+       { 0x2e000, 1, 0x1f, 0x1c0},
+       { 0x2e004, 255, 0x1f, 0x180},
+       { 0x2e400, 1, 0x1f, 0x1c0},
+       { 0x2e404, 255, 0x1f, 0x180},
+       { 0x2e800, 1, 0x1f, 0x1c0},
+       { 0x2e804, 255, 0x1f, 0x180},
+       { 0x2ec00, 1, 0x1f, 0x1c0},
+       { 0x2ec04, 255, 0x1f, 0x180},
+       { 0x2f000, 1, 0x1f, 0x1c0},
+       { 0x2f004, 255, 0x1f, 0x180},
+       { 0x2f400, 1, 0x1f, 0x1c0},
+       { 0x2f404, 255, 0x1f, 0x180},
+       { 0x2f800, 1, 0x1f, 0x1c0},
+       { 0x2f804, 255, 0x1f, 0x180},
+       { 0x2fc00, 1, 0x1f, 0x1c0},
+       { 0x2fc04, 255, 0x1f, 0x180},
+       { 0x30000, 1, 0x1f, 0x9e4},
+       { 0x30004, 255, 0x1f, 0x180},
+       { 0x30400, 1, 0x1f, 0x1c0},
+       { 0x30404, 255, 0x1f, 0x180},
+       { 0x30800, 1, 0x1f, 0x1c0},
+       { 0x30804, 255, 0x1f, 0x180},
+       { 0x30c00, 1, 0x1f, 0x1c0},
+       { 0x30c04, 255, 0x1f, 0x180},
+       { 0x31000, 1, 0x1f, 0x1c0},
+       { 0x31004, 255, 0x1f, 0x180},
+       { 0x31400, 1, 0x1f, 0x1c0},
+       { 0x31404, 255, 0x1f, 0x180},
+       { 0x31800, 1, 0x1f, 0x1c0},
+       { 0x31804, 255, 0x1f, 0x180},
+       { 0x31c00, 1, 0x1f, 0x1c0},
+       { 0x31c04, 255, 0x1f, 0x180},
+       { 0x32000, 1, 0x1f, 0x1c0},
+       { 0x32004, 255, 0x1f, 0x180},
+       { 0x32400, 1, 0x1f, 0x1c0},
+       { 0x32404, 255, 0x1f, 0x180},
+       { 0x32800, 1, 0x1f, 0x1c0},
+       { 0x32804, 255, 0x1f, 0x180},
+       { 0x32c00, 1, 0x1f, 0x1c0},
+       { 0x32c04, 255, 0x1f, 0x180},
+       { 0x33000, 1, 0x1f, 0x1c0},
+       { 0x33004, 255, 0x1f, 0x180},
+       { 0x33400, 1, 0x1f, 0x1c0},
+       { 0x33404, 255, 0x1f, 0x180},
+       { 0x33800, 1, 0x1f, 0x1c0},
+       { 0x33804, 255, 0x1f, 0x180},
+       { 0x33c00, 1, 0x1f, 0x1c0},
+       { 0x33c04, 255, 0x1f, 0x180},
+       { 0x34000, 1, 0x1f, 0x1c0},
+       { 0x34004, 255, 0x1f, 0x180},
+       { 0x34400, 1, 0x1f, 0x1c0},
+       { 0x34404, 255, 0x1f, 0x180},
+       { 0x34800, 1, 0x1f, 0x1c0},
+       { 0x34804, 255, 0x1f, 0x180},
+       { 0x34c00, 1, 0x1f, 0x1c0},
+       { 0x34c04, 255, 0x1f, 0x180},
+       { 0x35000, 1, 0x1f, 0x1c0},
+       { 0x35004, 255, 0x1f, 0x180},
+       { 0x35400, 1, 0x1f, 0x1c0},
+       { 0x35404, 255, 0x1f, 0x180},
+       { 0x35800, 1, 0x1f, 0x1c0},
+       { 0x35804, 255, 0x1f, 0x180},
+       { 0x35c00, 1, 0x1f, 0x1c0},
+       { 0x35c04, 255, 0x1f, 0x180},
+       { 0x36000, 1, 0x1f, 0x1c0},
+       { 0x36004, 255, 0x1f, 0x180},
+       { 0x36400, 1, 0x1f, 0x1c0},
+       { 0x36404, 255, 0x1f, 0x180},
+       { 0x36800, 1, 0x1f, 0x1c0},
+       { 0x36804, 255, 0x1f, 0x180},
+       { 0x36c00, 1, 0x1f, 0x1c0},
+       { 0x36c04, 255, 0x1f, 0x180},
+       { 0x37000, 1, 0x1f, 0x1c0},
+       { 0x37004, 255, 0x1f, 0x180},
+       { 0x37400, 1, 0x1f, 0x1c0},
+       { 0x37404, 255, 0x1f, 0x180},
+       { 0x37800, 1, 0x1f, 0x1c0},
+       { 0x37804, 255, 0x1f, 0x180},
+       { 0x37c00, 1, 0x1f, 0x1c0},
+       { 0x37c04, 255, 0x1f, 0x180},
+       { 0x38000, 1, 0x1f, 0x1c0},
+       { 0x38004, 255, 0x1f, 0x180},
+       { 0x38400, 1, 0x1f, 0x1c0},
+       { 0x38404, 255, 0x1f, 0x180},
+       { 0x38800, 1, 0x1f, 0x1c0},
+       { 0x38804, 255, 0x1f, 0x180},
+       { 0x38c00, 1, 0x1f, 0x1c0},
+       { 0x38c04, 255, 0x1f, 0x180},
+       { 0x39000, 1, 0x1f, 0x1c0},
+       { 0x39004, 255, 0x1f, 0x180},
+       { 0x39400, 1, 0x1f, 0x1c0},
+       { 0x39404, 255, 0x1f, 0x180},
+       { 0x39800, 1, 0x1f, 0x1c0},
+       { 0x39804, 255, 0x1f, 0x180},
+       { 0x39c00, 1, 0x1f, 0x1c0},
+       { 0x39c04, 255, 0x1f, 0x180},
+       { 0x3a000, 1, 0x1f, 0x1c0},
+       { 0x3a004, 255, 0x1f, 0x180},
+       { 0x3a400, 1, 0x1f, 0x1c0},
+       { 0x3a404, 255, 0x1f, 0x180},
+       { 0x3a800, 1, 0x1f, 0x1c0},
+       { 0x3a804, 255, 0x1f, 0x180},
+       { 0x3ac00, 1, 0x1f, 0x1c0},
+       { 0x3ac04, 255, 0x1f, 0x180},
+       { 0x3b000, 1, 0x1f, 0x1c0},
+       { 0x3b004, 255, 0x1f, 0x180},
+       { 0x3b400, 1, 0x1f, 0x1c0},
+       { 0x3b404, 255, 0x1f, 0x180},
+       { 0x3b800, 1, 0x1f, 0x1c0},
+       { 0x3b804, 255, 0x1f, 0x180},
+       { 0x3bc00, 1, 0x1f, 0x1c0},
+       { 0x3bc04, 255, 0x1f, 0x180},
+       { 0x3c000, 1, 0x1f, 0x1c0},
+       { 0x3c004, 255, 0x1f, 0x180},
+       { 0x3c400, 1, 0x1f, 0x1c0},
+       { 0x3c404, 255, 0x1f, 0x180},
+       { 0x3c800, 1, 0x1f, 0x1c0},
+       { 0x3c804, 255, 0x1f, 0x180},
+       { 0x3cc00, 1, 0x1f, 0x1c0},
+       { 0x3cc04, 255, 0x1f, 0x180},
+       { 0x3d000, 1, 0x1f, 0x1c0},
+       { 0x3d004, 255, 0x1f, 0x180},
+       { 0x3d400, 1, 0x1f, 0x1c0},
+       { 0x3d404, 255, 0x1f, 0x180},
+       { 0x3d800, 1, 0x1f, 0x1c0},
+       { 0x3d804, 255, 0x1f, 0x180},
+       { 0x3dc00, 1, 0x1f, 0x1c0},
+       { 0x3dc04, 255, 0x1f, 0x180},
+       { 0x3e000, 1, 0x1f, 0x1c0},
+       { 0x3e004, 255, 0x1f, 0x180},
+       { 0x3e400, 1, 0x1f, 0x1c0},
+       { 0x3e404, 255, 0x1f, 0x180},
+       { 0x3e800, 1, 0x1f, 0x1c0},
+       { 0x3e804, 255, 0x1f, 0x180},
+       { 0x3ec00, 1, 0x1f, 0x1c0},
+       { 0x3ec04, 255, 0x1f, 0x180},
+       { 0x3f000, 1, 0x1f, 0x1c0},
+       { 0x3f004, 255, 0x1f, 0x180},
+       { 0x3f400, 1, 0x1f, 0x1c0},
+       { 0x3f404, 255, 0x1f, 0x180},
+       { 0x3f800, 1, 0x1f, 0x1c0},
+       { 0x3f804, 255, 0x1f, 0x180},
+       { 0x3fc00, 1, 0x1f, 0x1c0},
+       { 0x3fc04, 255, 0x1f, 0x180},
+       { 0x40000, 85, 0x1f, 0x924},
+       { 0x40154, 13, 0x1f, 0xfff},
+       { 0x40198, 2, 0x1f, 0x1fff},
+       { 0x401a4, 1, 0x1f, 0x1fff},
+       { 0x401a8, 8, 0x1e, 0x924},
+       { 0x401c8, 1, 0x2, 0x924},
+       { 0x401cc, 2, 0x1e, 0x924},
+       { 0x401d4, 2, 0x1c, 0x924},
+       { 0x40200, 4, 0x1f, 0x924},
+       { 0x40220, 6, 0x1c, 0x924},
+       { 0x40238, 8, 0xc, 0x924},
+       { 0x40258, 4, 0x1c, 0x924},
+       { 0x40268, 2, 0x18, 0x924},
+       { 0x40270, 17, 0x10, 0x924},
+       { 0x40400, 43, 0x1f, 0x924},
+       { 0x404bc, 2, 0x1f, 0x1fff},
+       { 0x404c8, 1, 0x1f, 0x1fff},
+       { 0x404cc, 3, 0x1e, 0x924},
+       { 0x404e0, 1, 0x1c, 0x924},
+       { 0x40500, 2, 0x1f, 0x924},
+       { 0x40510, 2, 0x1f, 0x924},
+       { 0x40520, 2, 0x1f, 0x924},
+       { 0x40530, 2, 0x1f, 0x924},
+       { 0x40540, 2, 0x1f, 0x924},
+       { 0x40550, 10, 0x1c, 0x924},
+       { 0x40610, 2, 0x1c, 0x924},
+       { 0x42000, 164, 0x1f, 0x924},
+       { 0x422b0, 2, 0x1f, 0x1fff},
+       { 0x422bc, 1, 0x1f, 0x1fff},
+       { 0x422c0, 4, 0x1c, 0x924},
+       { 0x422d4, 5, 0x1e, 0x924},
+       { 0x422e8, 1, 0x1c, 0x924},
+       { 0x42400, 49, 0x1f, 0x924},
+       { 0x424c8, 32, 0x1f, 0x924},
+       { 0x42548, 1, 0x1f, 0xfff},
+       { 0x4254c, 1, 0x1f, 0x924},
+       { 0x42550, 1, 0x1f, 0xfff},
+       { 0x42554, 1, 0x1f, 0x924},
+       { 0x42558, 1, 0x1f, 0xfff},
+       { 0x4255c, 1, 0x1f, 0x924},
+       { 0x42568, 2, 0x1f, 0x924},
+       { 0x42640, 5, 0x1c, 0x924},
+       { 0x42800, 1, 0x1f, 0x924},
+       { 0x50000, 1, 0x1f, 0x1fff},
+       { 0x50004, 19, 0x1f, 0x924},
+       { 0x50050, 8, 0x1f, 0x93c},
+       { 0x50070, 60, 0x1f, 0x924},
+       { 0x50160, 8, 0x1f, 0xfff},
+       { 0x50180, 20, 0x1f, 0x924},
+       { 0x501e0, 2, 0x1f, 0x1fff},
+       { 0x501ec, 1, 0x1f, 0x1fff},
+       { 0x501f0, 4, 0x1e, 0x924},
+       { 0x50200, 1, 0x1f, 0x924},
+       { 0x50204, 1, 0x1f, 0xfff},
+       { 0x5020c, 2, 0x1f, 0xfff},
+       { 0x50214, 2, 0x1f, 0x924},
+       { 0x5021c, 1, 0x1f, 0xfff},
+       { 0x50220, 2, 0x1f, 0x924},
+       { 0x50228, 6, 0x1e, 0x924},
+       { 0x50240, 1, 0x1f, 0x924},
+       { 0x50280, 1, 0x1f, 0x924},
+       { 0x50300, 1, 0x1c, 0x924},
+       { 0x5030c, 1, 0x1c, 0x924},
+       { 0x50318, 1, 0x1c, 0x934},
+       { 0x5031c, 1, 0x1c, 0x924},
+       { 0x50320, 2, 0x1c, 0x934},
+       { 0x50330, 1, 0x10, 0x924},
+       { 0x52000, 1, 0x1f, 0x924},
+       { 0x54000, 1, 0x1f, 0x93c},
+       { 0x54004, 255, 0x1f, 0x30},
+       { 0x54400, 1, 0x1f, 0x38},
+       { 0x54404, 255, 0x1f, 0x30},
+       { 0x54800, 1, 0x1f, 0x38},
+       { 0x54804, 255, 0x1f, 0x30},
+       { 0x54c00, 1, 0x1f, 0x38},
+       { 0x54c04, 255, 0x1f, 0x30},
+       { 0x55000, 1, 0x1f, 0x38},
+       { 0x55004, 255, 0x1f, 0x30},
+       { 0x55400, 1, 0x1f, 0x38},
+       { 0x55404, 255, 0x1f, 0x30},
+       { 0x55800, 1, 0x1f, 0x38},
+       { 0x55804, 255, 0x1f, 0x30},
+       { 0x55c00, 1, 0x1f, 0x38},
+       { 0x55c04, 255, 0x1f, 0x30},
+       { 0x56000, 1, 0x1f, 0x38},
+       { 0x56004, 255, 0x1f, 0x30},
+       { 0x56400, 1, 0x1f, 0x38},
+       { 0x56404, 255, 0x1f, 0x30},
+       { 0x56800, 1, 0x1f, 0x38},
+       { 0x56804, 255, 0x1f, 0x30},
+       { 0x56c00, 1, 0x1f, 0x38},
+       { 0x56c04, 255, 0x1f, 0x30},
+       { 0x57000, 1, 0x1f, 0x38},
+       { 0x57004, 255, 0x1f, 0x30},
+       { 0x58000, 1, 0x1f, 0x934},
+       { 0x58004, 8191, 0x3, 0x30},
+       { 0x60000, 26, 0x1f, 0x924},
+       { 0x60068, 8, 0x3, 0x924},
+       { 0x60088, 2, 0x1f, 0x924},
+       { 0x60090, 1, 0x1f, 0xfff},
+       { 0x60094, 9, 0x1f, 0x924},
+       { 0x600b8, 9, 0x3, 0x924},
+       { 0x600dc, 1, 0x1f, 0x924},
+       { 0x600e0, 5, 0x3, 0x924},
+       { 0x600f4, 1, 0x7, 0x924},
+       { 0x600f8, 1, 0x3, 0x924},
+       { 0x600fc, 8, 0x1f, 0x924},
+       { 0x6012c, 2, 0x1f, 0x1fff},
+       { 0x60138, 1, 0x1f, 0x1fff},
+       { 0x6013c, 24, 0x2, 0x924},
+       { 0x6019c, 2, 0x1c, 0x924},
+       { 0x601ac, 18, 0x1c, 0x924},
+       { 0x60200, 1, 0x1f, 0xb6d},
+       { 0x60204, 2, 0x1f, 0x249},
+       { 0x60210, 13, 0x1c, 0x924},
+       { 0x60244, 16, 0x10, 0x924},
+       { 0x61000, 1, 0x1f, 0xb6d},
+       { 0x61004, 511, 0x1f, 0x249},
+       { 0x61800, 512, 0x18, 0x249},
+       { 0x70000, 8, 0x1f, 0xb6d},
+       { 0x70020, 8184, 0x1f, 0x249},
+       { 0x78000, 8192, 0x18, 0x249},
+       { 0x85000, 3, 0x1f, 0x1000},
+       { 0x8501c, 7, 0x1f, 0x1000},
+       { 0x85048, 1, 0x1f, 0x1000},
+       { 0x85200, 32, 0x1f, 0x1000},
+       { 0xa0000, 16384, 0x3, 0x1000},
+       { 0xb0000, 16384, 0x2, 0x1000},
+       { 0xc1000, 7, 0x1f, 0x924},
+       { 0xc102c, 2, 0x1f, 0x1fff},
+       { 0xc1038, 1, 0x1f, 0x1fff},
+       { 0xc103c, 2, 0x1c, 0x924},
+       { 0xc1800, 2, 0x1f, 0x924},
+       { 0xc2000, 164, 0x1f, 0x924},
+       { 0xc22b0, 2, 0x1f, 0x1fff},
+       { 0xc22bc, 1, 0x1f, 0x1fff},
+       { 0xc22c0, 5, 0x1c, 0x924},
+       { 0xc22d8, 4, 0x1c, 0x924},
+       { 0xc2400, 49, 0x1f, 0x924},
+       { 0xc24c8, 32, 0x1f, 0x924},
+       { 0xc2548, 1, 0x1f, 0xfff},
+       { 0xc254c, 1, 0x1f, 0x924},
+       { 0xc2550, 1, 0x1f, 0xfff},
+       { 0xc2554, 1, 0x1f, 0x924},
+       { 0xc2558, 1, 0x1f, 0xfff},
+       { 0xc255c, 1, 0x1f, 0x924},
+       { 0xc2568, 2, 0x1f, 0x924},
+       { 0xc2600, 1, 0x1f, 0x924},
+       { 0xc4000, 165, 0x1f, 0x924},
+       { 0xc42b4, 2, 0x1f, 0x1fff},
+       { 0xc42c0, 1, 0x1f, 0x1fff},
+       { 0xc42d8, 2, 0x1c, 0x924},
+       { 0xc42e0, 7, 0x1e, 0x924},
+       { 0xc42fc, 1, 0x1c, 0x924},
+       { 0xc4400, 51, 0x1f, 0x924},
+       { 0xc44d0, 32, 0x1f, 0x924},
+       { 0xc4550, 1, 0x1f, 0xfff},
+       { 0xc4554, 1, 0x1f, 0x924},
+       { 0xc4558, 1, 0x1f, 0xfff},
+       { 0xc455c, 1, 0x1f, 0x924},
+       { 0xc4560, 1, 0x1f, 0xfff},
+       { 0xc4564, 1, 0x1f, 0x924},
+       { 0xc4570, 2, 0x1f, 0x924},
+       { 0xc4578, 5, 0x1c, 0x924},
+       { 0xc4600, 1, 0x1f, 0x924},
+       { 0xd0000, 19, 0x1f, 0x924},
+       { 0xd004c, 8, 0x1f, 0x1927},
+       { 0xd006c, 64, 0x1f, 0x924},
+       { 0xd016c, 8, 0x1f, 0xfff},
+       { 0xd018c, 19, 0x1f, 0x924},
+       { 0xd01e8, 2, 0x1f, 0x1fff},
+       { 0xd01f4, 1, 0x1f, 0x1fff},
+       { 0xd01fc, 1, 0x1c, 0x924},
+       { 0xd0200, 1, 0x1f, 0x924},
+       { 0xd0204, 1, 0x1f, 0xfff},
+       { 0xd020c, 3, 0x1f, 0xfff},
+       { 0xd0218, 4, 0x1f, 0x924},
+       { 0xd0228, 18, 0x1e, 0x924},
+       { 0xd0280, 1, 0x1f, 0x924},
+       { 0xd0300, 1, 0x1f, 0x924},
+       { 0xd0400, 1, 0x1f, 0x924},
+       { 0xd0818, 1, 0x10, 0x924},
+       { 0xd4000, 1, 0x1f, 0x1927},
+       { 0xd4004, 255, 0x1f, 0x6},
+       { 0xd4400, 1, 0x1f, 0x1007},
+       { 0xd4404, 255, 0x1f, 0x6},
+       { 0xd4800, 1, 0x1f, 0x1007},
+       { 0xd4804, 255, 0x1f, 0x6},
+       { 0xd4c00, 1, 0x1f, 0x1007},
+       { 0xd4c04, 255, 0x1f, 0x6},
+       { 0xd5000, 1, 0x1f, 0x1007},
+       { 0xd5004, 255, 0x1f, 0x6},
+       { 0xd5400, 1, 0x1f, 0x1007},
+       { 0xd5404, 255, 0x1f, 0x6},
+       { 0xd5800, 1, 0x1f, 0x1007},
+       { 0xd5804, 255, 0x1f, 0x6},
+       { 0xd5c00, 1, 0x1f, 0x1007},
+       { 0xd5c04, 255, 0x1f, 0x6},
+       { 0xd6000, 1, 0x1f, 0x1007},
+       { 0xd6004, 255, 0x1f, 0x6},
+       { 0xd6400, 1, 0x1f, 0x1007},
+       { 0xd6404, 255, 0x1f, 0x6},
+       { 0xd8000, 1, 0x1f, 0x1927},
+       { 0xd8004, 255, 0x1f, 0x6},
+       { 0xd8400, 1, 0x1f, 0x1007},
+       { 0xd8404, 255, 0x1f, 0x6},
+       { 0xd8800, 1, 0x1f, 0x1007},
+       { 0xd8804, 255, 0x1f, 0x6},
+       { 0xd8c00, 1, 0x1f, 0x1007},
+       { 0xd8c04, 255, 0x1f, 0x6},
+       { 0xd9000, 1, 0x1f, 0x1007},
+       { 0xd9004, 255, 0x1f, 0x6},
+       { 0xd9400, 1, 0x1f, 0x1007},
+       { 0xd9404, 255, 0x1f, 0x6},
+       { 0xd9800, 1, 0x1f, 0x1007},
+       { 0xd9804, 255, 0x1f, 0x6},
+       { 0xd9c00, 1, 0x1f, 0x1007},
+       { 0xd9c04, 255, 0x1f, 0x6},
+       { 0xda000, 1, 0x1f, 0x1007},
+       { 0xda004, 255, 0x1f, 0x6},
+       { 0xda400, 1, 0x1f, 0x1007},
+       { 0xda404, 255, 0x1f, 0x6},
+       { 0xda800, 1, 0x1f, 0x1007},
+       { 0xda804, 255, 0x1f, 0x6},
+       { 0xdac00, 1, 0x1f, 0x1007},
+       { 0xdac04, 255, 0x1f, 0x6},
+       { 0xdb000, 1, 0x1f, 0x1007},
+       { 0xdb004, 255, 0x1f, 0x6},
+       { 0xdb400, 1, 0x1f, 0x1007},
+       { 0xdb404, 255, 0x1f, 0x6},
+       { 0xdb800, 1, 0x1f, 0x1007},
+       { 0xdb804, 255, 0x1f, 0x6},
+       { 0xdbc00, 1, 0x1f, 0x1007},
+       { 0xdbc04, 255, 0x1f, 0x6},
+       { 0xdc000, 1, 0x1f, 0x1007},
+       { 0xdc004, 255, 0x1f, 0x6},
+       { 0xdc400, 1, 0x1f, 0x1007},
+       { 0xdc404, 255, 0x1f, 0x6},
+       { 0xdc800, 1, 0x1f, 0x1007},
+       { 0xdc804, 255, 0x1f, 0x6},
+       { 0xdcc00, 1, 0x1f, 0x1007},
+       { 0xdcc04, 255, 0x1f, 0x6},
+       { 0xdd000, 1, 0x1f, 0x1007},
+       { 0xdd004, 255, 0x1f, 0x6},
+       { 0xdd400, 1, 0x1f, 0x1007},
+       { 0xdd404, 255, 0x1f, 0x6},
+       { 0xdd800, 1, 0x1f, 0x1007},
+       { 0xdd804, 255, 0x1f, 0x6},
+       { 0xddc00, 1, 0x1f, 0x1007},
+       { 0xddc04, 255, 0x1f, 0x6},
+       { 0xde000, 1, 0x1f, 0x1007},
+       { 0xde004, 255, 0x1f, 0x6},
+       { 0xde400, 1, 0x1f, 0x1007},
+       { 0xde404, 255, 0x1f, 0x6},
+       { 0xde800, 1, 0x1f, 0x1007},
+       { 0xde804, 255, 0x1f, 0x6},
+       { 0xdec00, 1, 0x1f, 0x1007},
+       { 0xdec04, 255, 0x1f, 0x6},
+       { 0xdf000, 1, 0x1f, 0x1007},
+       { 0xdf004, 255, 0x1f, 0x6},
+       { 0xdf400, 1, 0x1f, 0x1007},
+       { 0xdf404, 255, 0x1f, 0x6},
+       { 0xdf800, 1, 0x1f, 0x1007},
+       { 0xdf804, 255, 0x1f, 0x6},
+       { 0xdfc00, 1, 0x1f, 0x1007},
+       { 0xdfc04, 255, 0x1f, 0x6},
+       { 0xe0000, 21, 0x1f, 0x924},
+       { 0xe0054, 8, 0x1f, 0xf24},
+       { 0xe0074, 49, 0x1f, 0x924},
+       { 0xe0138, 1, 0x3, 0x924},
+       { 0xe013c, 6, 0x1f, 0x924},
+       { 0xe0154, 8, 0x1f, 0xfff},
+       { 0xe0174, 21, 0x1f, 0x924},
+       { 0xe01d8, 2, 0x1f, 0x1fff},
+       { 0xe01e4, 1, 0x1f, 0x1fff},
+       { 0xe01f4, 1, 0x4, 0x924},
+       { 0xe01f8, 1, 0x1c, 0x924},
+       { 0xe0200, 1, 0x1f, 0x924},
+       { 0xe0204, 1, 0x1f, 0xfff},
+       { 0xe020c, 2, 0x1f, 0xfff},
+       { 0xe0214, 2, 0x1f, 0x924},
+       { 0xe021c, 2, 0x1f, 0xfff},
+       { 0xe0224, 2, 0x1f, 0x924},
+       { 0xe022c, 18, 0x1e, 0x924},
+       { 0xe0280, 1, 0x1f, 0x924},
+       { 0xe0300, 1, 0x1f, 0x924},
+       { 0xe0400, 1, 0x10, 0x924},
+       { 0xe1000, 1, 0x1f, 0x924},
+       { 0xe2000, 1, 0x1f, 0xf24},
+       { 0xe2004, 255, 0x1f, 0xc00},
+       { 0xe2400, 1, 0x1f, 0xe00},
+       { 0xe2404, 255, 0x1f, 0xc00},
+       { 0xe2800, 1, 0x1f, 0xe00},
+       { 0xe2804, 255, 0x1f, 0xc00},
+       { 0xe2c00, 1, 0x1f, 0xe00},
+       { 0xe2c04, 255, 0x1f, 0xc00},
+       { 0xe3000, 1, 0x1f, 0xe00},
+       { 0xe3004, 255, 0x1f, 0xc00},
+       { 0xe3400, 1, 0x1f, 0xe00},
+       { 0xe3404, 255, 0x1f, 0xc00},
+       { 0xe3800, 1, 0x1f, 0xe00},
+       { 0xe3804, 255, 0x1f, 0xc00},
+       { 0xe3c00, 1, 0x1f, 0xe00},
+       { 0xe3c04, 255, 0x1f, 0xc00},
+       { 0xf0000, 1, 0x1f, 0xf24},
+       { 0xf0004, 255, 0x1f, 0xc00},
+       { 0xf0400, 1, 0x1f, 0xe00},
+       { 0xf0404, 255, 0x1f, 0xc00},
+       { 0xf0800, 1, 0x1f, 0xe00},
+       { 0xf0804, 255, 0x1f, 0xc00},
+       { 0xf0c00, 1, 0x1f, 0xe00},
+       { 0xf0c04, 255, 0x1f, 0xc00},
+       { 0xf1000, 1, 0x1f, 0xe00},
+       { 0xf1004, 255, 0x1f, 0xc00},
+       { 0xf1400, 1, 0x1f, 0xe00},
+       { 0xf1404, 255, 0x1f, 0xc00},
+       { 0xf1800, 1, 0x1f, 0xe00},
+       { 0xf1804, 255, 0x1f, 0xc00},
+       { 0xf1c00, 1, 0x1f, 0xe00},
+       { 0xf1c04, 255, 0x1f, 0xc00},
+       { 0xf2000, 1, 0x1f, 0xe00},
+       { 0xf2004, 255, 0x1f, 0xc00},
+       { 0xf2400, 1, 0x1f, 0xe00},
+       { 0xf2404, 255, 0x1f, 0xc00},
+       { 0xf2800, 1, 0x1f, 0xe00},
+       { 0xf2804, 255, 0x1f, 0xc00},
+       { 0xf2c00, 1, 0x1f, 0xe00},
+       { 0xf2c04, 255, 0x1f, 0xc00},
+       { 0xf3000, 1, 0x1f, 0xe00},
+       { 0xf3004, 255, 0x1f, 0xc00},
+       { 0xf3400, 1, 0x1f, 0xe00},
+       { 0xf3404, 255, 0x1f, 0xc00},
+       { 0xf3800, 1, 0x1f, 0xe00},
+       { 0xf3804, 255, 0x1f, 0xc00},
+       { 0xf3c00, 1, 0x1f, 0xe00},
+       { 0xf3c04, 255, 0x1f, 0xc00},
+       { 0xf4000, 1, 0x1f, 0xe00},
+       { 0xf4004, 255, 0x1f, 0xc00},
+       { 0xf4400, 1, 0x1f, 0xe00},
+       { 0xf4404, 255, 0x1f, 0xc00},
+       { 0xf4800, 1, 0x1f, 0xe00},
+       { 0xf4804, 255, 0x1f, 0xc00},
+       { 0xf4c00, 1, 0x1f, 0xe00},
+       { 0xf4c04, 255, 0x1f, 0xc00},
+       { 0xf5000, 1, 0x1f, 0xe00},
+       { 0xf5004, 255, 0x1f, 0xc00},
+       { 0xf5400, 1, 0x1f, 0xe00},
+       { 0xf5404, 255, 0x1f, 0xc00},
+       { 0xf5800, 1, 0x1f, 0xe00},
+       { 0xf5804, 255, 0x1f, 0xc00},
+       { 0xf5c00, 1, 0x1f, 0xe00},
+       { 0xf5c04, 255, 0x1f, 0xc00},
+       { 0xf6000, 1, 0x1f, 0xe00},
+       { 0xf6004, 255, 0x1f, 0xc00},
+       { 0xf6400, 1, 0x1f, 0xe00},
+       { 0xf6404, 255, 0x1f, 0xc00},
+       { 0xf6800, 1, 0x1f, 0xe00},
+       { 0xf6804, 255, 0x1f, 0xc00},
+       { 0xf6c00, 1, 0x1f, 0xe00},
+       { 0xf6c04, 255, 0x1f, 0xc00},
+       { 0xf7000, 1, 0x1f, 0xe00},
+       { 0xf7004, 255, 0x1f, 0xc00},
+       { 0xf7400, 1, 0x1f, 0xe00},
+       { 0xf7404, 255, 0x1f, 0xc00},
+       { 0xf7800, 1, 0x1f, 0xe00},
+       { 0xf7804, 255, 0x1f, 0xc00},
+       { 0xf7c00, 1, 0x1f, 0xe00},
+       { 0xf7c04, 255, 0x1f, 0xc00},
+       { 0xf8000, 1, 0x1f, 0xe00},
+       { 0xf8004, 255, 0x1f, 0xc00},
+       { 0xf8400, 1, 0x1f, 0xe00},
+       { 0xf8404, 255, 0x1f, 0xc00},
+       { 0xf8800, 1, 0x1f, 0xe00},
+       { 0xf8804, 255, 0x1f, 0xc00},
+       { 0xf8c00, 1, 0x1f, 0xe00},
+       { 0xf8c04, 255, 0x1f, 0xc00},
+       { 0xf9000, 1, 0x1f, 0xe00},
+       { 0xf9004, 255, 0x1f, 0xc00},
+       { 0xf9400, 1, 0x1f, 0xe00},
+       { 0xf9404, 255, 0x1f, 0xc00},
+       { 0xf9800, 1, 0x1f, 0xe00},
+       { 0xf9804, 255, 0x1f, 0xc00},
+       { 0xf9c00, 1, 0x1f, 0xe00},
+       { 0xf9c04, 255, 0x1f, 0xc00},
+       { 0xfa000, 1, 0x1f, 0xe00},
+       { 0xfa004, 255, 0x1f, 0xc00},
+       { 0xfa400, 1, 0x1f, 0xe00},
+       { 0xfa404, 255, 0x1f, 0xc00},
+       { 0xfa800, 1, 0x1f, 0xe00},
+       { 0xfa804, 255, 0x1f, 0xc00},
+       { 0xfac00, 1, 0x1f, 0xe00},
+       { 0xfac04, 255, 0x1f, 0xc00},
+       { 0xfb000, 1, 0x1f, 0xe00},
+       { 0xfb004, 255, 0x1f, 0xc00},
+       { 0xfb400, 1, 0x1f, 0xe00},
+       { 0xfb404, 255, 0x1f, 0xc00},
+       { 0xfb800, 1, 0x1f, 0xe00},
+       { 0xfb804, 255, 0x1f, 0xc00},
+       { 0xfbc00, 1, 0x1f, 0xe00},
+       { 0xfbc04, 255, 0x1f, 0xc00},
+       { 0xfc000, 1, 0x1f, 0xe00},
+       { 0xfc004, 255, 0x1f, 0xc00},
+       { 0xfc400, 1, 0x1f, 0xe00},
+       { 0xfc404, 255, 0x1f, 0xc00},
+       { 0xfc800, 1, 0x1f, 0xe00},
+       { 0xfc804, 255, 0x1f, 0xc00},
+       { 0xfcc00, 1, 0x1f, 0xe00},
+       { 0xfcc04, 255, 0x1f, 0xc00},
+       { 0xfd000, 1, 0x1f, 0xe00},
+       { 0xfd004, 255, 0x1f, 0xc00},
+       { 0xfd400, 1, 0x1f, 0xe00},
+       { 0xfd404, 255, 0x1f, 0xc00},
+       { 0xfd800, 1, 0x1f, 0xe00},
+       { 0xfd804, 255, 0x1f, 0xc00},
+       { 0xfdc00, 1, 0x1f, 0xe00},
+       { 0xfdc04, 255, 0x1f, 0xc00},
+       { 0xfe000, 1, 0x1f, 0xe00},
+       { 0xfe004, 255, 0x1f, 0xc00},
+       { 0xfe400, 1, 0x1f, 0xe00},
+       { 0xfe404, 255, 0x1f, 0xc00},
+       { 0xfe800, 1, 0x1f, 0xe00},
+       { 0xfe804, 255, 0x1f, 0xc00},
+       { 0xfec00, 1, 0x1f, 0xe00},
+       { 0xfec04, 255, 0x1f, 0xc00},
+       { 0xff000, 1, 0x1f, 0xe00},
+       { 0xff004, 255, 0x1f, 0xc00},
+       { 0xff400, 1, 0x1f, 0xe00},
+       { 0xff404, 255, 0x1f, 0xc00},
+       { 0xff800, 1, 0x1f, 0xe00},
+       { 0xff804, 255, 0x1f, 0xc00},
+       { 0xffc00, 1, 0x1f, 0xe00},
+       { 0xffc04, 255, 0x1f, 0xc00},
+       { 0x101000, 5, 0x1f, 0x924},
+       { 0x101014, 1, 0x1f, 0xfff},
+       { 0x101018, 6, 0x1f, 0x924},
+       { 0x101040, 2, 0x1f, 0x1fff},
+       { 0x10104c, 1, 0x1f, 0x1fff},
+       { 0x101050, 1, 0x1e, 0x924},
+       { 0x101054, 3, 0x1c, 0x924},
+       { 0x101100, 1, 0x1f, 0x924},
+       { 0x101800, 8, 0x1f, 0x924},
+       { 0x102000, 18, 0x1f, 0x924},
+       { 0x102058, 2, 0x1f, 0x1fff},
+       { 0x102064, 1, 0x1f, 0x1fff},
+       { 0x102068, 6, 0x1c, 0x924},
+       { 0x102080, 16, 0x1f, 0xfff},
+       { 0x1020c0, 1, 0x1f, 0x924},
+       { 0x1020c8, 8, 0x2, 0x924},
+       { 0x1020e8, 9, 0x1c, 0x924},
+       { 0x102400, 1, 0x1f, 0x924},
+       { 0x103000, 1, 0x1f, 0x924},
+       { 0x103004, 2, 0x1f, 0xfff},
+       { 0x10300c, 23, 0x1f, 0x924},
+       { 0x103088, 2, 0x1f, 0x1fff},
+       { 0x103094, 1, 0x1f, 0x1fff},
+       { 0x103098, 1, 0x1e, 0x924},
+       { 0x10309c, 2, 0x1e, 0xfff},
+       { 0x1030a4, 2, 0x1e, 0x924},
+       { 0x1030ac, 2, 0x1c, 0x924},
+       { 0x1030b4, 1, 0x4, 0x924},
+       { 0x1030b8, 2, 0x1c, 0xfff},
+       { 0x1030c0, 3, 0x1c, 0x924},
+       { 0x1030cc, 1, 0x1c, 0xfff},
+       { 0x1030d0, 1, 0x1c, 0x924},
+       { 0x1030d8, 2, 0x1c, 0x924},
+       { 0x1030e0, 1, 0x1c, 0xfff},
+       { 0x1030e4, 5, 0x1c, 0x924},
+       { 0x103400, 136, 0x1c, 0x1fff},
+       { 0x103800, 8, 0x1f, 0x924},
+       { 0x104000, 1, 0x1f, 0x924},
+       { 0x104004, 1, 0x1f, 0xfff},
+       { 0x104008, 4, 0x1f, 0x924},
+       { 0x104018, 1, 0x1f, 0xfff},
+       { 0x10401c, 1, 0x1f, 0x924},
+       { 0x104020, 1, 0x1f, 0xfff},
+       { 0x104024, 6, 0x1f, 0x924},
+       { 0x10403c, 1, 0x1f, 0xfff},
+       { 0x104040, 47, 0x1f, 0x924},
+       { 0x10410c, 2, 0x1f, 0x1fff},
+       { 0x104118, 1, 0x1f, 0x1fff},
+       { 0x10411c, 16, 0x1c, 0x924},
+       { 0x104200, 17, 0x1f, 0x924},
+       { 0x104400, 1, 0x1f, 0x1fff},
+       { 0x104404, 63, 0x1f, 0xfff},
+       { 0x104500, 192, 0x1f, 0xdb6},
+       { 0x104800, 1, 0x1f, 0x1fff},
+       { 0x104804, 63, 0x1f, 0xfff},
+       { 0x104900, 192, 0x1f, 0xdb6},
+       { 0x105000, 4, 0x1f, 0x1fff},
+       { 0x105010, 252, 0x1f, 0xfff},
+       { 0x105400, 768, 0x1f, 0xdb6},
+       { 0x107000, 7, 0x1c, 0x924},
+       { 0x10701c, 1, 0x18, 0x924},
+       { 0x108000, 33, 0x3, 0x924},
+       { 0x1080ac, 5, 0x2, 0x924},
+       { 0x108100, 5, 0x3, 0x924},
+       { 0x108120, 5, 0x3, 0x924},
+       { 0x108200, 74, 0x3, 0x924},
+       { 0x108400, 74, 0x3, 0x924},
+       { 0x108800, 152, 0x3, 0x924},
+       { 0x110000, 111, 0x1c, 0x924},
+       { 0x1101cc, 2, 0x1c, 0x1fff},
+       { 0x1101d8, 1, 0x1c, 0x1fff},
+       { 0x1101dc, 1, 0x18, 0x924},
+       { 0x110200, 4, 0x1c, 0x924},
+       { 0x120000, 92, 0x1f, 0x924},
+       { 0x120170, 2, 0x3, 0x924},
+       { 0x120178, 14, 0x1f, 0x924},
+       { 0x1201b0, 2, 0x1f, 0xfff},
+       { 0x1201b8, 93, 0x1f, 0x924},
+       { 0x12032c, 1, 0x1f, 0xfff},
+       { 0x120330, 15, 0x1f, 0x924},
+       { 0x12036c, 3, 0x1f, 0xfff},
+       { 0x120378, 36, 0x1f, 0x924},
+       { 0x120408, 2, 0x1f, 0xfff},
+       { 0x120410, 1, 0x1f, 0x924},
+       { 0x120414, 15, 0x1f, 0xfff},
+       { 0x120450, 10, 0x1f, 0x924},
+       { 0x120478, 2, 0x1f, 0xfff},
+       { 0x120480, 43, 0x1f, 0x924},
+       { 0x12052c, 1, 0x1f, 0xfff},
+       { 0x120530, 5, 0x1f, 0x924},
+       { 0x120544, 4, 0x3, 0x924},
+       { 0x120554, 4, 0x1f, 0x924},
+       { 0x120564, 2, 0x1f, 0xfff},
+       { 0x12057c, 2, 0x1f, 0x1fff},
+       { 0x120588, 3, 0x1f, 0x1fff},
+       { 0x120598, 1, 0x1f, 0x1fff},
+       { 0x12059c, 22, 0x1e, 0x924},
+       { 0x1205f4, 1, 0x6, 0x924},
+       { 0x1205f8, 4, 0x1c, 0x924},
+       { 0x120618, 1, 0x1c, 0x924},
+       { 0x12061c, 31, 0x1e, 0x924},
+       { 0x120698, 3, 0x1c, 0x924},
+       { 0x1206a4, 1, 0x4, 0x924},
+       { 0x1206a8, 1, 0x1c, 0x924},
+       { 0x1206b0, 38, 0x1c, 0x924},
+       { 0x120748, 1, 0x1c, 0xfff},
+       { 0x12074c, 11, 0x1c, 0x924},
+       { 0x120778, 2, 0x1c, 0xfff},
+       { 0x120780, 23, 0x1c, 0x924},
+       { 0x1207dc, 1, 0x4, 0x924},
+       { 0x1207fc, 1, 0x1c, 0x924},
+       { 0x12080c, 2, 0x1f, 0xfff},
+       { 0x120814, 1, 0x1f, 0x924},
+       { 0x120818, 1, 0x1f, 0xfff},
+       { 0x12081c, 1, 0x1f, 0x924},
+       { 0x120820, 1, 0x1f, 0xfff},
+       { 0x120824, 1, 0x1f, 0x924},
+       { 0x120828, 1, 0x1f, 0xfff},
+       { 0x12082c, 1, 0x1f, 0x924},
+       { 0x120830, 1, 0x1f, 0xfff},
+       { 0x120834, 1, 0x1f, 0x924},
+       { 0x120838, 1, 0x1f, 0xfff},
+       { 0x12083c, 1, 0x1f, 0x924},
+       { 0x120840, 1, 0x1f, 0xfff},
+       { 0x120844, 1, 0x1f, 0x924},
+       { 0x120848, 1, 0x1f, 0xfff},
+       { 0x12084c, 1, 0x1f, 0x924},
+       { 0x120850, 1, 0x1f, 0xfff},
+       { 0x120854, 1, 0x1f, 0x924},
+       { 0x120858, 1, 0x1f, 0xfff},
+       { 0x12085c, 1, 0x1f, 0x924},
+       { 0x120860, 1, 0x1f, 0xfff},
+       { 0x120864, 1, 0x1f, 0x924},
+       { 0x120868, 1, 0x1f, 0xfff},
+       { 0x12086c, 1, 0x1f, 0x924},
+       { 0x120870, 1, 0x1f, 0xfff},
+       { 0x120874, 1, 0x1f, 0x924},
+       { 0x120878, 1, 0x1f, 0xfff},
+       { 0x12087c, 1, 0x1f, 0x924},
+       { 0x120880, 1, 0x1f, 0xfff},
+       { 0x120884, 1, 0x1f, 0x924},
+       { 0x120888, 1, 0x1f, 0xfff},
+       { 0x12088c, 1, 0x1f, 0x924},
+       { 0x120890, 1, 0x1f, 0xfff},
+       { 0x120894, 1, 0x1f, 0x924},
+       { 0x120898, 1, 0x1f, 0xfff},
+       { 0x12089c, 1, 0x1f, 0x924},
+       { 0x1208a0, 1, 0x1f, 0xfff},
+       { 0x1208a4, 1, 0x1f, 0x924},
+       { 0x1208a8, 1, 0x1f, 0xfff},
+       { 0x1208ac, 1, 0x1f, 0x924},
+       { 0x1208b0, 1, 0x1f, 0xfff},
+       { 0x1208b4, 1, 0x1f, 0x924},
+       { 0x1208b8, 1, 0x1f, 0xfff},
+       { 0x1208bc, 1, 0x1f, 0x924},
+       { 0x1208c0, 1, 0x1f, 0xfff},
+       { 0x1208c4, 1, 0x1f, 0x924},
+       { 0x1208c8, 1, 0x1f, 0xfff},
+       { 0x1208cc, 1, 0x1f, 0x924},
+       { 0x1208d0, 1, 0x1f, 0xfff},
+       { 0x1208d4, 1, 0x1f, 0x924},
+       { 0x1208d8, 1, 0x1f, 0xfff},
+       { 0x1208dc, 1, 0x1f, 0x924},
+       { 0x1208e0, 1, 0x1f, 0xfff},
+       { 0x1208e4, 1, 0x1f, 0x924},
+       { 0x1208e8, 1, 0x1f, 0xfff},
+       { 0x1208ec, 1, 0x1f, 0x924},
+       { 0x1208f0, 1, 0x1f, 0xfff},
+       { 0x1208f4, 1, 0x1f, 0x924},
+       { 0x1208f8, 1, 0x1f, 0xfff},
+       { 0x1208fc, 1, 0x1f, 0x924},
+       { 0x120900, 1, 0x1f, 0xfff},
+       { 0x120904, 1, 0x1f, 0x924},
+       { 0x120908, 1, 0x1f, 0xfff},
+       { 0x12090c, 1, 0x1f, 0x924},
+       { 0x120910, 7, 0x1c, 0x924},
+       { 0x120930, 9, 0x1c, 0x924},
+       { 0x12095c, 37, 0x18, 0x924},
+       { 0x120a00, 2, 0x7, 0x924},
+       { 0x120b00, 1, 0x18, 0x924},
+       { 0x122000, 2, 0x1f, 0x924},
+       { 0x122008, 2046, 0x1, 0x924},
+       { 0x128000, 6144, 0x1e, 0x924},
+       { 0x130000, 1, 0x1c, 0x1fff},
+       { 0x130004, 11, 0x1c, 0x924},
+       { 0x130030, 1, 0x1c, 0xfff},
+       { 0x130034, 6, 0x1c, 0x924},
+       { 0x13004c, 3, 0x1c, 0xfff},
+       { 0x130058, 3, 0x1c, 0x924},
+       { 0x130064, 2, 0x1c, 0xfff},
+       { 0x13006c, 8, 0x1c, 0x924},
+       { 0x13009c, 2, 0x1c, 0x1fff},
+       { 0x1300a8, 1, 0x1c, 0x1fff},
+       { 0x130100, 12, 0x1c, 0x924},
+       { 0x130130, 1, 0x1c, 0xfff},
+       { 0x130134, 14, 0x1c, 0x924},
+       { 0x13016c, 1, 0x1c, 0xfff},
+       { 0x130170, 1, 0x1c, 0x924},
+       { 0x130180, 1, 0x1c, 0x924},
+       { 0x130200, 1, 0x1c, 0x924},
+       { 0x130280, 1, 0x1c, 0x924},
+       { 0x130300, 1, 0x1c, 0xfff},
+       { 0x130304, 4, 0x1c, 0x924},
+       { 0x130380, 1, 0x1c, 0x924},
+       { 0x130400, 1, 0x1c, 0x924},
+       { 0x130480, 1, 0x1c, 0xfff},
+       { 0x130484, 4, 0x1c, 0x924},
+       { 0x130800, 72, 0x1c, 0x924},
+       { 0x131000, 136, 0x1c, 0x924},
+       { 0x132000, 148, 0x1c, 0x924},
+       { 0x134000, 544, 0x1c, 0x924},
+       { 0x140000, 1, 0x1f, 0x924},
+       { 0x140004, 9, 0xf, 0x924},
+       { 0x140028, 8, 0x1f, 0x924},
+       { 0x140048, 5, 0xf, 0x924},
+       { 0x14005c, 2, 0xf, 0xfff},
+       { 0x140064, 3, 0xf, 0x924},
+       { 0x140070, 1, 0x1f, 0x924},
+       { 0x140074, 10, 0xf, 0x924},
+       { 0x14009c, 1, 0x1f, 0x924},
+       { 0x1400a0, 5, 0xf, 0x924},
+       { 0x1400b4, 7, 0x1f, 0x924},
+       { 0x1400d0, 2, 0xf, 0xfff},
+       { 0x1400d8, 2, 0xf, 0x924},
+       { 0x1400e0, 1, 0xf, 0xfff},
+       { 0x1400e4, 5, 0xf, 0x924},
+       { 0x1400f8, 2, 0x1f, 0x924},
+       { 0x140100, 5, 0x3, 0x924},
+       { 0x140114, 5, 0xf, 0x924},
+       { 0x140128, 7, 0x1f, 0x924},
+       { 0x140144, 9, 0xf, 0x924},
+       { 0x140168, 8, 0x1f, 0x924},
+       { 0x140188, 3, 0xf, 0x924},
+       { 0x140194, 13, 0x1f, 0x924},
+       { 0x1401d8, 2, 0x1f, 0x1fff},
+       { 0x1401e4, 1, 0x1f, 0x1fff},
+       { 0x140200, 6, 0xf, 0xfff},
+       { 0x1402e0, 2, 0xc, 0x924},
+       { 0x1402e8, 2, 0x1c, 0x924},
+       { 0x1402f0, 9, 0xc, 0x924},
+       { 0x140314, 9, 0x10, 0x924},
+       { 0x140338, 7, 0x10, 0xfff},
+       { 0x140354, 7, 0x10, 0x924},
+       { 0x140370, 7, 0x10, 0xfff},
+       { 0x14038c, 14, 0x10, 0x924},
+       { 0x1404b0, 14, 0x10, 0x924},
+       { 0x15c000, 2, 0x1e, 0x924},
+       { 0x15c008, 5, 0x2, 0x924},
+       { 0x15c020, 8, 0x1c, 0x924},
+       { 0x15c040, 1, 0xc, 0x924},
+       { 0x15c044, 2, 0x1c, 0x924},
+       { 0x15c04c, 8, 0xc, 0x924},
+       { 0x15c06c, 8, 0x1c, 0x924},
+       { 0x15c090, 13, 0x1c, 0x924},
+       { 0x15c0c8, 24, 0x1c, 0x924},
+       { 0x15c128, 2, 0xc, 0x924},
+       { 0x15c130, 1, 0x1c, 0x924},
+       { 0x15c138, 6, 0x1c, 0x924},
+       { 0x15c150, 2, 0x18, 0x924},
+       { 0x15c158, 2, 0x8, 0x924},
+       { 0x15c160, 23, 0x10, 0x924},
+       { 0x15c1bc, 6, 0x10, 0xfff},
+       { 0x15c1d4, 23, 0x10, 0x924},
+       { 0x15c230, 7, 0x10, 0xfff},
+       { 0x15c24c, 90, 0x10, 0x924},
+       { 0x160004, 6, 0x18, 0x924},
+       { 0x16003c, 1, 0x10, 0x924},
+       { 0x160040, 6, 0x18, 0x924},
+       { 0x16005c, 6, 0x18, 0x924},
+       { 0x160074, 1, 0x10, 0x924},
+       { 0x160078, 2, 0x18, 0x924},
+       { 0x160300, 8, 0x18, 0x924},
+       { 0x160330, 6, 0x18, 0x924},
+       { 0x160404, 6, 0x18, 0x924},
+       { 0x16043c, 1, 0x10, 0x924},
+       { 0x160440, 6, 0x18, 0x924},
+       { 0x16045c, 6, 0x18, 0x924},
+       { 0x160474, 1, 0x10, 0x924},
+       { 0x160478, 2, 0x18, 0x924},
+       { 0x160700, 8, 0x18, 0x924},
+       { 0x160730, 6, 0x18, 0x924},
+       { 0x161000, 7, 0x1f, 0x924},
+       { 0x16102c, 2, 0x1f, 0x1fff},
+       { 0x161038, 1, 0x1f, 0x1fff},
+       { 0x16103c, 2, 0x1c, 0x924},
+       { 0x161800, 2, 0x1f, 0x924},
+       { 0x162000, 54, 0x18, 0x924},
+       { 0x162200, 60, 0x18, 0x924},
+       { 0x162400, 54, 0x18, 0x924},
+       { 0x162600, 60, 0x18, 0x924},
+       { 0x162800, 54, 0x18, 0x924},
+       { 0x162a00, 60, 0x18, 0x924},
+       { 0x162c00, 54, 0x18, 0x924},
+       { 0x162e00, 60, 0x18, 0x924},
+       { 0x163000, 1, 0x18, 0x924},
+       { 0x163008, 1, 0x18, 0x924},
+       { 0x163010, 1, 0x18, 0x924},
+       { 0x163018, 1, 0x18, 0x924},
+       { 0x163020, 5, 0x18, 0x924},
+       { 0x163038, 3, 0x18, 0x924},
+       { 0x163048, 3, 0x18, 0x924},
+       { 0x163058, 1, 0x18, 0x924},
+       { 0x163060, 1, 0x18, 0x924},
+       { 0x163068, 1, 0x18, 0x924},
+       { 0x163070, 3, 0x18, 0x924},
+       { 0x163080, 1, 0x18, 0x924},
+       { 0x163088, 3, 0x18, 0x924},
+       { 0x163098, 1, 0x18, 0x924},
+       { 0x1630a0, 1, 0x18, 0x924},
+       { 0x1630a8, 1, 0x18, 0x924},
+       { 0x1630b0, 2, 0x10, 0x924},
+       { 0x1630c0, 1, 0x18, 0x924},
+       { 0x1630c8, 1, 0x18, 0x924},
+       { 0x1630d0, 1, 0x18, 0x924},
+       { 0x1630d8, 1, 0x18, 0x924},
+       { 0x1630e0, 2, 0x18, 0x924},
+       { 0x163110, 1, 0x18, 0x924},
+       { 0x163120, 2, 0x18, 0x924},
+       { 0x163420, 4, 0x18, 0x924},
+       { 0x163438, 2, 0x18, 0x924},
+       { 0x163488, 2, 0x18, 0x924},
+       { 0x163520, 2, 0x18, 0x924},
+       { 0x163800, 1, 0x18, 0x924},
+       { 0x163808, 1, 0x18, 0x924},
+       { 0x163810, 1, 0x18, 0x924},
+       { 0x163818, 1, 0x18, 0x924},
+       { 0x163820, 5, 0x18, 0x924},
+       { 0x163838, 3, 0x18, 0x924},
+       { 0x163848, 3, 0x18, 0x924},
+       { 0x163858, 1, 0x18, 0x924},
+       { 0x163860, 1, 0x18, 0x924},
+       { 0x163868, 1, 0x18, 0x924},
+       { 0x163870, 3, 0x18, 0x924},
+       { 0x163880, 1, 0x18, 0x924},
+       { 0x163888, 3, 0x18, 0x924},
+       { 0x163898, 1, 0x18, 0x924},
+       { 0x1638a0, 1, 0x18, 0x924},
+       { 0x1638a8, 1, 0x18, 0x924},
+       { 0x1638b0, 2, 0x10, 0x924},
+       { 0x1638c0, 1, 0x18, 0x924},
+       { 0x1638c8, 1, 0x18, 0x924},
+       { 0x1638d0, 1, 0x18, 0x924},
+       { 0x1638d8, 1, 0x18, 0x924},
+       { 0x1638e0, 2, 0x18, 0x924},
+       { 0x163910, 1, 0x18, 0x924},
+       { 0x163920, 2, 0x18, 0x924},
+       { 0x163c20, 4, 0x18, 0x924},
+       { 0x163c38, 2, 0x18, 0x924},
+       { 0x163c88, 2, 0x18, 0x924},
+       { 0x163d20, 2, 0x18, 0x924},
+       { 0x164000, 5, 0x1f, 0x924},
+       { 0x164014, 2, 0x1f, 0xfff},
+       { 0x16401c, 53, 0x1f, 0x924},
+       { 0x164100, 2, 0x1f, 0x1fff},
+       { 0x16410c, 1, 0x1f, 0x1fff},
+       { 0x164110, 2, 0x1e, 0x924},
+       { 0x164118, 15, 0x1c, 0x924},
+       { 0x164200, 1, 0x1f, 0x924},
+       { 0x164208, 1, 0x1f, 0x924},
+       { 0x164210, 1, 0x1f, 0x924},
+       { 0x164218, 1, 0x1f, 0x924},
+       { 0x164220, 1, 0x1f, 0x924},
+       { 0x164228, 1, 0x1f, 0x924},
+       { 0x164230, 1, 0x1f, 0x924},
+       { 0x164238, 1, 0x1f, 0x924},
+       { 0x164240, 1, 0x1f, 0x924},
+       { 0x164248, 1, 0x1f, 0x924},
+       { 0x164250, 1, 0x1f, 0x924},
+       { 0x164258, 1, 0x1f, 0x924},
+       { 0x164260, 1, 0x1f, 0x924},
+       { 0x164270, 2, 0x1f, 0x924},
+       { 0x164280, 2, 0x1f, 0x924},
+       { 0x164800, 2, 0x1f, 0x924},
+       { 0x165000, 2, 0x1f, 0x924},
+       { 0x166000, 164, 0x1f, 0x924},
+       { 0x1662b0, 2, 0x1f, 0x1fff},
+       { 0x1662bc, 1, 0x1f, 0x1fff},
+       { 0x1662cc, 7, 0x1c, 0x924},
+       { 0x166400, 49, 0x1f, 0x924},
+       { 0x1664c8, 32, 0x1f, 0x924},
+       { 0x166548, 1, 0x1f, 0xfff},
+       { 0x16654c, 1, 0x1f, 0x924},
+       { 0x166550, 1, 0x1f, 0xfff},
+       { 0x166554, 1, 0x1f, 0x924},
+       { 0x166558, 1, 0x1f, 0xfff},
+       { 0x16655c, 1, 0x1f, 0x924},
+       { 0x166568, 2, 0x1f, 0x924},
+       { 0x166570, 5, 0x1c, 0x924},
+       { 0x166800, 1, 0x1f, 0x924},
+       { 0x168000, 1, 0x1f, 0xfff},
+       { 0x168004, 1, 0x1f, 0x924},
+       { 0x168008, 1, 0x1f, 0xfff},
+       { 0x16800c, 1, 0x1f, 0x924},
+       { 0x168010, 1, 0x1f, 0xfff},
+       { 0x168014, 1, 0x1f, 0x924},
+       { 0x168018, 1, 0x1f, 0xfff},
+       { 0x16801c, 3, 0x1f, 0x924},
+       { 0x168028, 2, 0x1f, 0xfff},
+       { 0x168030, 10, 0x1f, 0x924},
+       { 0x168058, 9, 0x1f, 0xfff},
+       { 0x16807c, 106, 0x1f, 0x924},
+       { 0x168224, 2, 0x3, 0x924},
+       { 0x16822c, 3, 0x1f, 0x924},
+       { 0x168238, 1, 0x1f, 0xfff},
+       { 0x16823c, 25, 0x1f, 0x924},
+       { 0x1682a0, 12, 0x3, 0x924},
+       { 0x1682d0, 7, 0x1f, 0xfff},
+       { 0x1682ec, 5, 0x1f, 0x924},
+       { 0x168300, 2, 0x3, 0xfff},
+       { 0x168308, 65, 0x1f, 0xfff},
+       { 0x16840c, 1, 0x1f, 0x924},
+       { 0x168410, 2, 0x1f, 0xfff},
+       { 0x168418, 2, 0x3, 0x924},
+       { 0x168420, 6, 0x1f, 0x924},
+       { 0x168448, 2, 0x1f, 0x1fff},
+       { 0x168454, 1, 0x1f, 0x1fff},
+       { 0x168800, 19, 0x1f, 0x924},
+       { 0x168900, 1, 0x1f, 0x924},
+       { 0x168a00, 128, 0x1f, 0xfff},
+       { 0x16a000, 1536, 0x1f, 0x924},
+       { 0x16c000, 1536, 0x1f, 0x924},
+       { 0x16e000, 16, 0x2, 0x924},
+       { 0x16e040, 8, 0x1c, 0x924},
+       { 0x16e100, 1, 0x2, 0x924},
+       { 0x16e200, 2, 0x2, 0xfff},
+       { 0x16e400, 1, 0x2, 0x924},
+       { 0x16e404, 2, 0x2, 0xfff},
+       { 0x16e40c, 94, 0x2, 0x924},
+       { 0x16e584, 64, 0x2, 0xfff},
+       { 0x16e684, 2, 0x1e, 0xfff},
+       { 0x16e68c, 4, 0x2, 0xfff},
+       { 0x16e69c, 8, 0x2, 0x924},
+       { 0x16e6bc, 4, 0x1e, 0x924},
+       { 0x16e6cc, 4, 0x2, 0x924},
+       { 0x16e6e0, 2, 0x1c, 0x924},
+       { 0x16e6e8, 5, 0xc, 0x924},
+       { 0x16e6fc, 4, 0x1c, 0xfff},
+       { 0x16e70c, 1, 0x1c, 0x924},
+       { 0x16e768, 17, 0x1c, 0x924},
+       { 0x16e7ac, 12, 0x10, 0xfff},
+       { 0x170000, 24, 0x1f, 0x924},
+       { 0x170060, 4, 0x3, 0x924},
+       { 0x170070, 13, 0x1f, 0x924},
+       { 0x1700a4, 1, 0x1f, 0xfff},
+       { 0x1700a8, 1, 0x1f, 0x924},
+       { 0x1700ac, 2, 0x1f, 0xfff},
+       { 0x1700b4, 3, 0x1f, 0x924},
+       { 0x1700c0, 1, 0x1f, 0xfff},
+       { 0x1700c4, 44, 0x1f, 0x924},
+       { 0x170184, 2, 0x1f, 0x1fff},
+       { 0x170190, 1, 0x1f, 0x1fff},
+       { 0x170194, 11, 0x1c, 0x924},
+       { 0x1701c4, 1, 0x1c, 0x924},
+       { 0x1701cc, 7, 0x1c, 0x924},
+       { 0x1701e8, 1, 0x18, 0x924},
+       { 0x1701ec, 1, 0x1c, 0x924},
+       { 0x1701f4, 1, 0x1c, 0x924},
+       { 0x170200, 4, 0x1f, 0x924},
+       { 0x170214, 1, 0x1f, 0x924},
+       { 0x170218, 77, 0x1c, 0x924},
+       { 0x170400, 64, 0x1c, 0x924},
+       { 0x178000, 1, 0x1f, 0x924},
+       { 0x180000, 61, 0x1f, 0x924},
+       { 0x180114, 2, 0x1f, 0x1fff},
+       { 0x180120, 3, 0x1f, 0x1fff},
+       { 0x180130, 1, 0x1f, 0x1fff},
+       { 0x18013c, 2, 0x1e, 0x924},
+       { 0x180200, 27, 0x1f, 0x924},
+       { 0x18026c, 1, 0x1f, 0xfff},
+       { 0x180270, 12, 0x1f, 0x924},
+       { 0x1802a0, 1, 0x1f, 0xfff},
+       { 0x1802a4, 17, 0x1f, 0x924},
+       { 0x180340, 4, 0x1f, 0x924},
+       { 0x180380, 1, 0x1c, 0x924},
+       { 0x180388, 1, 0x1c, 0x924},
+       { 0x180390, 1, 0x1c, 0x924},
+       { 0x180398, 1, 0x1c, 0x924},
+       { 0x1803a0, 5, 0x1c, 0x924},
+       { 0x1803b4, 2, 0x18, 0x924},
+       { 0x180400, 256, 0x3, 0xfff},
+       { 0x181000, 4, 0x1f, 0x93c},
+       { 0x181010, 1020, 0x1f, 0x38},
+       { 0x182000, 4, 0x18, 0x924},
+       { 0x1a0000, 1, 0x1f, 0x92c},
+       { 0x1a0004, 5631, 0x1f, 0x8},
+       { 0x1a5800, 2560, 0x1e, 0x8},
+       { 0x1a8000, 1, 0x1f, 0x92c},
+       { 0x1a8004, 8191, 0x1e, 0x8},
+       { 0x1b0000, 1, 0x1f, 0x92c},
+       { 0x1b0004, 15, 0x2, 0x8},
+       { 0x1b0040, 1, 0x1e, 0x92c},
+       { 0x1b0044, 239, 0x2, 0x8},
+       { 0x1b0400, 1, 0x1f, 0x92c},
+       { 0x1b0404, 255, 0x2, 0x8},
+       { 0x1b0800, 1, 0x1f, 0x924},
+       { 0x1b0840, 1, 0x1e, 0x924},
+       { 0x1b0c00, 1, 0x1f, 0x1fff},
+       { 0x1b1000, 1, 0x1f, 0x1fff},
+       { 0x1b1040, 1, 0x1e, 0x1fff},
+       { 0x1b1400, 1, 0x1f, 0x924},
+       { 0x1b1440, 1, 0x1e, 0x924},
+       { 0x1b1480, 1, 0x1e, 0x924},
+       { 0x1b14c0, 1, 0x1e, 0x924},
+       { 0x1b1800, 128, 0x1f, 0x10},
+       { 0x1b1c00, 128, 0x1f, 0x10},
+       { 0x1b2000, 1, 0x1f, 0xdb6},
+       { 0x1b2400, 1, 0x1e, 0x92c},
+       { 0x1b2404, 5631, 0x1c, 0x8},
+       { 0x1b8000, 1, 0x1f, 0xfff},
+       { 0x1b8040, 1, 0x1f, 0xfff},
+       { 0x1b8080, 1, 0x1f, 0xfff},
+       { 0x1b80c0, 1, 0x1f, 0xfff},
+       { 0x1b8100, 1, 0x1f, 0x924},
+       { 0x1b8140, 1, 0x1f, 0x924},
+       { 0x1b8180, 1, 0x1f, 0x924},
+       { 0x1b81c0, 1, 0x1f, 0x924},
+       { 0x1b8200, 1, 0x1f, 0x924},
+       { 0x1b8240, 1, 0x1f, 0x924},
+       { 0x1b8280, 1, 0x1f, 0x924},
+       { 0x1b82c0, 1, 0x1f, 0x924},
+       { 0x1b8300, 1, 0x1f, 0x924},
+       { 0x1b8340, 1, 0x1f, 0x924},
+       { 0x1b8380, 1, 0x1f, 0x924},
+       { 0x1b83c0, 1, 0x1f, 0x924},
+       { 0x1b8400, 1, 0x1f, 0x924},
+       { 0x1b8440, 1, 0x1f, 0x924},
+       { 0x1b8480, 1, 0x1f, 0x924},
+       { 0x1b84c0, 1, 0x1f, 0x924},
+       { 0x1b8500, 1, 0x1f, 0x924},
+       { 0x1b8540, 1, 0x1f, 0x924},
+       { 0x1b8580, 1, 0x1f, 0x924},
+       { 0x1b85c0, 19, 0x1c, 0x924},
+       { 0x1b8800, 1, 0x1f, 0x924},
+       { 0x1b8840, 1, 0x1f, 0x924},
+       { 0x1b8880, 1, 0x1f, 0x924},
+       { 0x1b88c0, 1, 0x1f, 0x924},
+       { 0x1b8900, 1, 0x1f, 0x924},
+       { 0x1b8940, 1, 0x1f, 0x924},
+       { 0x1b8980, 1, 0x1f, 0x924},
+       { 0x1b89c0, 1, 0x1f, 0x924},
+       { 0x1b8a00, 1, 0x1f, 0x934},
+       { 0x1b8a40, 1, 0x1f, 0x924},
+       { 0x1b8a80, 1, 0x1f, 0x492},
+       { 0x1b8ac0, 1, 0x1f, 0x924},
+       { 0x1b8b00, 1, 0x1f, 0x924},
+       { 0x1b8b40, 1, 0x1f, 0x924},
+       { 0x1b8b80, 1, 0x1f, 0x924},
+       { 0x1b8bc0, 1, 0x1f, 0x924},
+       { 0x1b8c00, 1, 0x1f, 0x924},
+       { 0x1b8c40, 1, 0x1f, 0x924},
+       { 0x1b8c80, 1, 0x1f, 0x924},
+       { 0x1b8cc0, 1, 0x1f, 0x924},
+       { 0x1b8cc4, 1, 0x1c, 0x924},
+       { 0x1b8d00, 1, 0x1f, 0x924},
+       { 0x1b8d40, 1, 0x1f, 0x924},
+       { 0x1b8d80, 1, 0x1f, 0x924},
+       { 0x1b8dc0, 1, 0x1f, 0x924},
+       { 0x1b8e00, 1, 0x1f, 0x924},
+       { 0x1b8e40, 1, 0x1f, 0x924},
+       { 0x1b8e80, 1, 0x1f, 0x924},
+       { 0x1b8e84, 1, 0x1c, 0x924},
+       { 0x1b8ec0, 1, 0x1e, 0x924},
+       { 0x1b8f00, 1, 0x1e, 0x924},
+       { 0x1b8f40, 1, 0x1e, 0x924},
+       { 0x1b8f80, 1, 0x1e, 0x924},
+       { 0x1b8fc0, 1, 0x1e, 0x924},
+       { 0x1b8fd4, 5, 0x1c, 0x924},
+       { 0x1b8fe8, 2, 0x18, 0x924},
+       { 0x1b9000, 1, 0x1c, 0x924},
+       { 0x1b9040, 3, 0x1c, 0x924},
+       { 0x1b905c, 1, 0x18, 0x924},
+       { 0x1b9064, 1, 0x10, 0x924},
+       { 0x1b9080, 10, 0x10, 0x924},
+       { 0x1c0000, 2, 0x1f, 0x924},
+       { 0x200000, 65, 0x1f, 0x924},
+       { 0x200124, 2, 0x1f, 0x1fff},
+       { 0x200130, 3, 0x1f, 0x1fff},
+       { 0x200140, 1, 0x1f, 0x1fff},
+       { 0x20014c, 2, 0x1e, 0x924},
+       { 0x200200, 27, 0x1f, 0x924},
+       { 0x20026c, 1, 0x1f, 0xfff},
+       { 0x200270, 12, 0x1f, 0x924},
+       { 0x2002a0, 1, 0x1f, 0xfff},
+       { 0x2002a4, 17, 0x1f, 0x924},
+       { 0x200340, 4, 0x1f, 0x924},
+       { 0x200380, 1, 0x1c, 0x924},
+       { 0x200388, 1, 0x1c, 0x924},
+       { 0x200390, 1, 0x1c, 0x924},
+       { 0x200398, 1, 0x1c, 0x924},
+       { 0x2003a0, 1, 0x1c, 0x924},
+       { 0x2003a8, 2, 0x1c, 0x924},
+       { 0x200400, 256, 0x3, 0xfff},
+       { 0x202000, 4, 0x1f, 0x1927},
+       { 0x202010, 2044, 0x1f, 0x1007},
+       { 0x204000, 4, 0x18, 0x924},
+       { 0x220000, 1, 0x1f, 0x925},
+       { 0x220004, 5631, 0x1f, 0x1},
+       { 0x225800, 2560, 0x1e, 0x1},
+       { 0x228000, 1, 0x1f, 0x925},
+       { 0x228004, 8191, 0x1e, 0x1},
+       { 0x230000, 1, 0x1f, 0x925},
+       { 0x230004, 15, 0x2, 0x1},
+       { 0x230040, 1, 0x1e, 0x925},
+       { 0x230044, 239, 0x2, 0x1},
+       { 0x230400, 1, 0x1f, 0x925},
+       { 0x230404, 255, 0x2, 0x1},
+       { 0x230800, 1, 0x1f, 0x924},
+       { 0x230840, 1, 0x1e, 0x924},
+       { 0x230c00, 1, 0x1f, 0x924},
+       { 0x231000, 1, 0x1f, 0x924},
+       { 0x231040, 1, 0x1e, 0x924},
+       { 0x231400, 1, 0x1f, 0x924},
+       { 0x231440, 1, 0x1e, 0x924},
+       { 0x231480, 1, 0x1e, 0x924},
+       { 0x2314c0, 1, 0x1e, 0x924},
+       { 0x231800, 128, 0x1f, 0x2},
+       { 0x231c00, 128, 0x1f, 0x2},
+       { 0x232000, 1, 0x1f, 0xdb6},
+       { 0x232400, 1, 0x1e, 0x925},
+       { 0x232404, 5631, 0x1c, 0x1},
+       { 0x238000, 1, 0x1f, 0xfff},
+       { 0x238040, 1, 0x1f, 0xfff},
+       { 0x238080, 1, 0x1f, 0xfff},
+       { 0x2380c0, 1, 0x1f, 0xfff},
+       { 0x238100, 1, 0x1f, 0x924},
+       { 0x238140, 1, 0x1f, 0x924},
+       { 0x238180, 1, 0x1f, 0x924},
+       { 0x2381c0, 1, 0x1f, 0x924},
+       { 0x238200, 1, 0x1f, 0x924},
+       { 0x238240, 1, 0x1f, 0x924},
+       { 0x238280, 1, 0x1f, 0x924},
+       { 0x2382c0, 1, 0x1f, 0x924},
+       { 0x238300, 1, 0x1f, 0x924},
+       { 0x238340, 1, 0x1f, 0x924},
+       { 0x238380, 1, 0x1f, 0x924},
+       { 0x2383c0, 1, 0x1f, 0x924},
+       { 0x238400, 1, 0x1f, 0x924},
+       { 0x238440, 1, 0x1f, 0x924},
+       { 0x238480, 1, 0x1f, 0x924},
+       { 0x2384c0, 1, 0x1f, 0x924},
+       { 0x238500, 1, 0x1f, 0x924},
+       { 0x238540, 1, 0x1f, 0x924},
+       { 0x238580, 1, 0x1f, 0x924},
+       { 0x2385c0, 19, 0x1c, 0x924},
+       { 0x238800, 1, 0x1f, 0x924},
+       { 0x238840, 1, 0x1f, 0x924},
+       { 0x238880, 1, 0x1f, 0x924},
+       { 0x2388c0, 1, 0x1f, 0x924},
+       { 0x238900, 1, 0x1f, 0x924},
+       { 0x238940, 1, 0x1f, 0x924},
+       { 0x238980, 1, 0x1f, 0x924},
+       { 0x2389c0, 1, 0x1f, 0x924},
+       { 0x238a00, 1, 0x1f, 0x926},
+       { 0x238a40, 1, 0x1f, 0x924},
+       { 0x238a80, 1, 0x1f, 0x492},
+       { 0x238ac0, 1, 0x1f, 0x924},
+       { 0x238b00, 1, 0x1f, 0x924},
+       { 0x238b40, 1, 0x1f, 0x924},
+       { 0x238b80, 1, 0x1f, 0x924},
+       { 0x238bc0, 1, 0x1f, 0x924},
+       { 0x238c00, 1, 0x1f, 0x924},
+       { 0x238c40, 1, 0x1f, 0x924},
+       { 0x238c80, 1, 0x1f, 0x924},
+       { 0x238cc0, 1, 0x1f, 0x924},
+       { 0x238cc4, 1, 0x1c, 0x924},
+       { 0x238d00, 1, 0x1f, 0x924},
+       { 0x238d40, 1, 0x1f, 0x924},
+       { 0x238d80, 1, 0x1f, 0x924},
+       { 0x238dc0, 1, 0x1f, 0x924},
+       { 0x238e00, 1, 0x1f, 0x924},
+       { 0x238e40, 1, 0x1f, 0x924},
+       { 0x238e80, 1, 0x1f, 0x924},
+       { 0x238e84, 1, 0x1c, 0x924},
+       { 0x238ec0, 1, 0x1e, 0x924},
+       { 0x238f00, 1, 0x1e, 0x924},
+       { 0x238f40, 1, 0x1e, 0x924},
+       { 0x238f80, 1, 0x1e, 0x924},
+       { 0x238fc0, 1, 0x1e, 0x924},
+       { 0x238fd4, 5, 0x1c, 0x924},
+       { 0x238fe8, 2, 0x18, 0x924},
+       { 0x239000, 1, 0x1c, 0x924},
+       { 0x239040, 3, 0x1c, 0x924},
+       { 0x23905c, 1, 0x18, 0x924},
+       { 0x239064, 1, 0x10, 0x924},
+       { 0x239080, 10, 0x10, 0x924},
+       { 0x240000, 2, 0x1f, 0x924},
+       { 0x280000, 65, 0x1f, 0x924},
+       { 0x280124, 2, 0x1f, 0x1fff},
+       { 0x280130, 3, 0x1f, 0x1fff},
+       { 0x280140, 1, 0x1f, 0x1fff},
+       { 0x28014c, 2, 0x1e, 0x924},
+       { 0x280200, 27, 0x1f, 0x924},
+       { 0x28026c, 1, 0x1f, 0xfff},
+       { 0x280270, 12, 0x1f, 0x924},
+       { 0x2802a0, 1, 0x1f, 0xfff},
+       { 0x2802a4, 17, 0x1f, 0x924},
+       { 0x280340, 4, 0x1f, 0x924},
+       { 0x280380, 1, 0x1c, 0x924},
+       { 0x280388, 1, 0x1c, 0x924},
+       { 0x280390, 1, 0x1c, 0x924},
+       { 0x280398, 1, 0x1c, 0x924},
+       { 0x2803a0, 1, 0x1c, 0x924},
+       { 0x2803a8, 2, 0x1c, 0x924},
+       { 0x280400, 256, 0x3, 0xfff},
+       { 0x282000, 4, 0x1f, 0x9e4},
+       { 0x282010, 2044, 0x1f, 0x1c0},
+       { 0x284000, 4, 0x18, 0x924},
+       { 0x2a0000, 1, 0x1f, 0x964},
+       { 0x2a0004, 5631, 0x1f, 0x40},
+       { 0x2a5800, 2560, 0x1e, 0x40},
+       { 0x2a8000, 1, 0x1f, 0x964},
+       { 0x2a8004, 8191, 0x1e, 0x40},
+       { 0x2b0000, 1, 0x1f, 0x964},
+       { 0x2b0004, 15, 0x2, 0x40},
+       { 0x2b0040, 1, 0x1e, 0x964},
+       { 0x2b0044, 239, 0x2, 0x40},
+       { 0x2b0400, 1, 0x1f, 0x964},
+       { 0x2b0404, 255, 0x2, 0x40},
+       { 0x2b0800, 1, 0x1f, 0x924},
+       { 0x2b0840, 1, 0x1e, 0x924},
+       { 0x2b0c00, 1, 0x1f, 0x924},
+       { 0x2b1000, 1, 0x1f, 0x924},
+       { 0x2b1040, 1, 0x1e, 0x924},
+       { 0x2b1400, 1, 0x1f, 0x924},
+       { 0x2b1440, 1, 0x1e, 0x924},
+       { 0x2b1480, 1, 0x1e, 0x924},
+       { 0x2b14c0, 1, 0x1e, 0x924},
+       { 0x2b1800, 128, 0x1f, 0x80},
+       { 0x2b1c00, 128, 0x1f, 0x80},
+       { 0x2b2000, 1, 0x1f, 0xdb6},
+       { 0x2b2400, 1, 0x1e, 0x964},
+       { 0x2b2404, 5631, 0x1c, 0x40},
+       { 0x2b8000, 1, 0x1f, 0xfff},
+       { 0x2b8040, 1, 0x1f, 0xfff},
+       { 0x2b8080, 1, 0x1f, 0xfff},
+       { 0x2b80c0, 1, 0x1f, 0x924},
+       { 0x2b8100, 1, 0x1f, 0x924},
+       { 0x2b8140, 1, 0x1f, 0x924},
+       { 0x2b8180, 1, 0x1f, 0x924},
+       { 0x2b81c0, 1, 0x1f, 0x924},
+       { 0x2b8200, 1, 0x1f, 0x924},
+       { 0x2b8240, 1, 0x1f, 0x924},
+       { 0x2b8280, 1, 0x1f, 0x924},
+       { 0x2b82c0, 1, 0x1f, 0x924},
+       { 0x2b8300, 1, 0x1f, 0x924},
+       { 0x2b8340, 1, 0x1f, 0x924},
+       { 0x2b8380, 1, 0x1f, 0x924},
+       { 0x2b83c0, 1, 0x1f, 0x924},
+       { 0x2b8400, 1, 0x1f, 0x924},
+       { 0x2b8440, 1, 0x1f, 0x924},
+       { 0x2b8480, 1, 0x1f, 0x924},
+       { 0x2b84c0, 1, 0x1f, 0x924},
+       { 0x2b8500, 1, 0x1f, 0x924},
+       { 0x2b8540, 1, 0x1f, 0x924},
+       { 0x2b8580, 1, 0x1f, 0x924},
+       { 0x2b85c0, 19, 0x1c, 0x924},
+       { 0x2b8800, 1, 0x1f, 0x924},
+       { 0x2b8840, 1, 0x1f, 0x924},
+       { 0x2b8880, 1, 0x1f, 0x924},
+       { 0x2b88c0, 1, 0x1f, 0x924},
+       { 0x2b8900, 1, 0x1f, 0x924},
+       { 0x2b8940, 1, 0x1f, 0x924},
+       { 0x2b8980, 1, 0x1f, 0x924},
+       { 0x2b89c0, 1, 0x1f, 0x924},
+       { 0x2b8a00, 1, 0x1f, 0x9a4},
+       { 0x2b8a40, 1, 0x1f, 0x924},
+       { 0x2b8a80, 1, 0x1f, 0x492},
+       { 0x2b8ac0, 1, 0x1f, 0x924},
+       { 0x2b8b00, 1, 0x1f, 0x924},
+       { 0x2b8b40, 1, 0x1f, 0x924},
+       { 0x2b8b80, 1, 0x1f, 0x924},
+       { 0x2b8bc0, 1, 0x1f, 0x924},
+       { 0x2b8c00, 1, 0x1f, 0x924},
+       { 0x2b8c40, 1, 0x1f, 0x924},
+       { 0x2b8c80, 1, 0x1f, 0x924},
+       { 0x2b8cc0, 1, 0x1f, 0x924},
+       { 0x2b8cc4, 1, 0x1c, 0x924},
+       { 0x2b8d00, 1, 0x1f, 0x924},
+       { 0x2b8d40, 1, 0x1f, 0x924},
+       { 0x2b8d80, 1, 0x1f, 0x924},
+       { 0x2b8dc0, 1, 0x1f, 0x924},
+       { 0x2b8e00, 1, 0x1f, 0x924},
+       { 0x2b8e40, 1, 0x1f, 0x924},
+       { 0x2b8e80, 1, 0x1f, 0x924},
+       { 0x2b8e84, 1, 0x1c, 0x924},
+       { 0x2b8ec0, 1, 0x1e, 0x924},
+       { 0x2b8f00, 1, 0x1e, 0x924},
+       { 0x2b8f40, 1, 0x1e, 0x924},
+       { 0x2b8f80, 1, 0x1e, 0x924},
+       { 0x2b8fc0, 1, 0x1e, 0x924},
+       { 0x2b8fd4, 5, 0x1c, 0x924},
+       { 0x2b8fe8, 2, 0x18, 0x924},
+       { 0x2b9000, 1, 0x1c, 0x924},
+       { 0x2b9040, 3, 0x1c, 0x924},
+       { 0x2b905c, 1, 0x18, 0x924},
+       { 0x2b9064, 1, 0x10, 0x924},
+       { 0x2b9080, 10, 0x10, 0x924},
+       { 0x2c0000, 2, 0x1f, 0x1fff},
+       { 0x300000, 65, 0x1f, 0x924},
+       { 0x300124, 2, 0x1f, 0x1fff},
+       { 0x300130, 3, 0x1f, 0x1fff},
+       { 0x300140, 1, 0x1f, 0x1fff},
+       { 0x30014c, 2, 0x1e, 0x924},
+       { 0x300200, 27, 0x1f, 0x924},
+       { 0x30026c, 1, 0x1f, 0xfff},
+       { 0x300270, 12, 0x1f, 0x924},
+       { 0x3002a0, 1, 0x1f, 0xfff},
+       { 0x3002a4, 17, 0x1f, 0x924},
+       { 0x300340, 4, 0x1f, 0x924},
+       { 0x300380, 1, 0x1c, 0x924},
+       { 0x300388, 1, 0x1c, 0x924},
+       { 0x300390, 1, 0x1c, 0x924},
+       { 0x300398, 1, 0x1c, 0x924},
+       { 0x3003a0, 1, 0x1c, 0x924},
+       { 0x3003a8, 2, 0x1c, 0x924},
+       { 0x300400, 256, 0x3, 0xfff},
+       { 0x302000, 4, 0x1f, 0xf24},
+       { 0x302010, 2044, 0x1f, 0xe00},
+       { 0x304000, 4, 0x18, 0x924},
+       { 0x320000, 1, 0x1f, 0xb24},
+       { 0x320004, 5631, 0x1f, 0x200},
+       { 0x325800, 2560, 0x1e, 0x200},
+       { 0x328000, 1, 0x1f, 0xb24},
+       { 0x328004, 8191, 0x1e, 0x200},
+       { 0x330000, 1, 0x1f, 0xb24},
+       { 0x330004, 15, 0x2, 0x200},
+       { 0x330040, 1, 0x1e, 0xb24},
+       { 0x330044, 239, 0x2, 0x200},
+       { 0x330400, 1, 0x1f, 0xb24},
+       { 0x330404, 255, 0x2, 0x200},
+       { 0x330800, 1, 0x1f, 0x924},
+       { 0x330840, 1, 0x1e, 0x924},
+       { 0x330c00, 1, 0x1f, 0x924},
+       { 0x331000, 1, 0x1f, 0x924},
+       { 0x331040, 1, 0x1e, 0x924},
+       { 0x331400, 1, 0x1f, 0x924},
+       { 0x331440, 1, 0x1e, 0x924},
+       { 0x331480, 1, 0x1e, 0x924},
+       { 0x3314c0, 1, 0x1e, 0x924},
+       { 0x331800, 128, 0x1f, 0x400},
+       { 0x331c00, 128, 0x1f, 0x400},
+       { 0x332000, 1, 0x1f, 0xdb6},
+       { 0x332400, 1, 0x1e, 0xb24},
+       { 0x332404, 5631, 0x1c, 0x200},
+       { 0x338000, 1, 0x1f, 0xfff},
+       { 0x338040, 1, 0x1f, 0xfff},
+       { 0x338080, 1, 0x1f, 0xfff},
+       { 0x3380c0, 1, 0x1f, 0xfff},
+       { 0x338100, 1, 0x1f, 0x924},
+       { 0x338140, 1, 0x1f, 0x924},
+       { 0x338180, 1, 0x1f, 0x924},
+       { 0x3381c0, 1, 0x1f, 0x924},
+       { 0x338200, 1, 0x1f, 0x924},
+       { 0x338240, 1, 0x1f, 0x924},
+       { 0x338280, 1, 0x1f, 0x924},
+       { 0x3382c0, 1, 0x1f, 0x924},
+       { 0x338300, 1, 0x1f, 0x924},
+       { 0x338340, 1, 0x1f, 0x924},
+       { 0x338380, 1, 0x1f, 0x924},
+       { 0x3383c0, 1, 0x1f, 0x924},
+       { 0x338400, 1, 0x1f, 0x924},
+       { 0x338440, 1, 0x1f, 0x924},
+       { 0x338480, 1, 0x1f, 0x924},
+       { 0x3384c0, 1, 0x1f, 0x924},
+       { 0x338500, 1, 0x1f, 0x924},
+       { 0x338540, 1, 0x1f, 0x924},
+       { 0x338580, 1, 0x1f, 0x924},
+       { 0x3385c0, 19, 0x1c, 0x924},
+       { 0x338800, 1, 0x1f, 0x924},
+       { 0x338840, 1, 0x1f, 0x924},
+       { 0x338880, 1, 0x1f, 0x924},
+       { 0x3388c0, 1, 0x1f, 0x924},
+       { 0x338900, 1, 0x1f, 0x924},
+       { 0x338940, 1, 0x1f, 0x924},
+       { 0x338980, 1, 0x1f, 0x924},
+       { 0x3389c0, 1, 0x1f, 0x924},
+       { 0x338a00, 1, 0x1f, 0xd24},
+       { 0x338a40, 1, 0x1f, 0x924},
+       { 0x338a80, 1, 0x1f, 0x492},
+       { 0x338ac0, 1, 0x1f, 0x924},
+       { 0x338b00, 1, 0x1f, 0x924},
+       { 0x338b40, 1, 0x1f, 0x924},
+       { 0x338b80, 1, 0x1f, 0x924},
+       { 0x338bc0, 1, 0x1f, 0x924},
+       { 0x338c00, 1, 0x1f, 0x924},
+       { 0x338c40, 1, 0x1f, 0x924},
+       { 0x338c80, 1, 0x1f, 0x924},
+       { 0x338cc0, 1, 0x1f, 0x924},
+       { 0x338cc4, 1, 0x1c, 0x924},
+       { 0x338d00, 1, 0x1f, 0x924},
+       { 0x338d40, 1, 0x1f, 0x924},
+       { 0x338d80, 1, 0x1f, 0x924},
+       { 0x338dc0, 1, 0x1f, 0x924},
+       { 0x338e00, 1, 0x1f, 0x924},
+       { 0x338e40, 1, 0x1f, 0x924},
+       { 0x338e80, 1, 0x1f, 0x924},
+       { 0x338e84, 1, 0x1c, 0x924},
+       { 0x338ec0, 1, 0x1e, 0x924},
+       { 0x338f00, 1, 0x1e, 0x924},
+       { 0x338f40, 1, 0x1e, 0x924},
+       { 0x338f80, 1, 0x1e, 0x924},
+       { 0x338fc0, 1, 0x1e, 0x924},
+       { 0x338fd4, 5, 0x1c, 0x924},
+       { 0x338fe8, 2, 0x18, 0x924},
+       { 0x339000, 1, 0x1c, 0x924},
+       { 0x339040, 3, 0x1c, 0x924},
+       { 0x33905c, 1, 0x18, 0x924},
+       { 0x339064, 1, 0x10, 0x924},
+       { 0x339080, 10, 0x10, 0x924},
+       { 0x340000, 2, 0x1f, 0x924},
+       { 0x3a0000, 40960, 0x1c, 0x1000}
 };
-#define REGS_COUNT                     ARRAY_SIZE(reg_addrs)
 
-static const struct dump_sign dump_sign_all = { 0x4e23fde1, 0x70017, 0x3a };
+#define REGS_COUNT ARRAY_SIZE(reg_addrs)
 
-static const u32 page_vals_e2[] = { 0, 128 };
-#define PAGE_MODE_VALUES_E2            ARRAY_SIZE(page_vals_e2)
+static const struct reg_addr idle_reg_addrs[] = {
+       { 0x2104, 1, 0x1f, 0xfff},
+       { 0x2110, 2, 0x1f, 0xfff},
+       { 0x211c, 8, 0x1f, 0xfff},
+       { 0x2814, 1, 0x1f, 0xfff},
+       { 0x281c, 2, 0x1f, 0xfff},
+       { 0x2854, 1, 0x1f, 0xfff},
+       { 0x285c, 1, 0x1f, 0xfff},
+       { 0x3040, 1, 0x1f, 0xfff},
+       { 0x9010, 7, 0x1c, 0xfff},
+       { 0x9030, 1, 0x1c, 0xfff},
+       { 0x9068, 16, 0x1c, 0xfff},
+       { 0x9230, 2, 0x1c, 0xfff},
+       { 0x9244, 1, 0x1c, 0xfff},
+       { 0x9298, 1, 0x1c, 0xfff},
+       { 0x92a8, 1, 0x1c, 0x1fff},
+       { 0xa38c, 1, 0x1f, 0x1fff},
+       { 0xa3c4, 1, 0x1e, 0xfff},
+       { 0xa404, 1, 0x1f, 0xfff},
+       { 0xa408, 2, 0x1f, 0x1fff},
+       { 0xa42c, 12, 0x1f, 0xfff},
+       { 0xa580, 1, 0x1f, 0x1fff},
+       { 0xa590, 1, 0x1f, 0x1fff},
+       { 0xa600, 5, 0x1e, 0xfff},
+       { 0xa618, 1, 0x1e, 0xfff},
+       { 0xa714, 1, 0x1c, 0xfff},
+       { 0xa720, 1, 0x1c, 0xfff},
+       { 0xa750, 1, 0x1c, 0xfff},
+       { 0xc09c, 1, 0x3, 0xfff},
+       { 0x103b0, 1, 0x1f, 0xfff},
+       { 0x103c0, 1, 0x1f, 0xfff},
+       { 0x103d0, 1, 0x3, 0x1fff},
+       { 0x10418, 1, 0x1f, 0xfff},
+       { 0x10420, 1, 0x1f, 0xfff},
+       { 0x10428, 1, 0x1f, 0xfff},
+       { 0x10460, 1, 0x1f, 0xfff},
+       { 0x10474, 1, 0x1f, 0xfff},
+       { 0x104e0, 1, 0x1f, 0xfff},
+       { 0x104ec, 1, 0x1f, 0xfff},
+       { 0x104f8, 1, 0x1f, 0xfff},
+       { 0x10508, 1, 0x1f, 0xfff},
+       { 0x10530, 1, 0x1f, 0xfff},
+       { 0x10538, 1, 0x1f, 0xfff},
+       { 0x10548, 1, 0x1f, 0xfff},
+       { 0x10558, 1, 0x1f, 0xfff},
+       { 0x182a8, 1, 0x1c, 0xfff},
+       { 0x182b8, 1, 0x1c, 0xfff},
+       { 0x18308, 1, 0x1c, 0xfff},
+       { 0x18318, 1, 0x1c, 0xfff},
+       { 0x18338, 1, 0x1c, 0xfff},
+       { 0x18348, 1, 0x1c, 0xfff},
+       { 0x183bc, 1, 0x1c, 0x1fff},
+       { 0x183cc, 1, 0x1c, 0x1fff},
+       { 0x18570, 1, 0x18, 0xfff},
+       { 0x18578, 1, 0x18, 0xfff},
+       { 0x1858c, 1, 0x18, 0xfff},
+       { 0x18594, 1, 0x18, 0xfff},
+       { 0x1862c, 4, 0x10, 0xfff},
+       { 0x2021c, 11, 0x1f, 0xfff},
+       { 0x202a8, 1, 0x1f, 0xfff},
+       { 0x202b8, 1, 0x1f, 0x1fff},
+       { 0x20404, 1, 0x1f, 0xfff},
+       { 0x2040c, 2, 0x1f, 0xfff},
+       { 0x2041c, 2, 0x1f, 0xfff},
+       { 0x40154, 14, 0x1f, 0xfff},
+       { 0x40198, 1, 0x1f, 0x1fff},
+       { 0x404ac, 1, 0x1f, 0xfff},
+       { 0x404bc, 1, 0x1f, 0x1fff},
+       { 0x42290, 1, 0x1f, 0xfff},
+       { 0x422a0, 1, 0x1f, 0xfff},
+       { 0x422b0, 1, 0x1f, 0x1fff},
+       { 0x42548, 1, 0x1f, 0xfff},
+       { 0x42550, 1, 0x1f, 0xfff},
+       { 0x42558, 1, 0x1f, 0xfff},
+       { 0x50160, 8, 0x1f, 0xfff},
+       { 0x501d0, 1, 0x1f, 0xfff},
+       { 0x501e0, 1, 0x1f, 0x1fff},
+       { 0x50204, 1, 0x1f, 0xfff},
+       { 0x5020c, 2, 0x1f, 0xfff},
+       { 0x5021c, 1, 0x1f, 0xfff},
+       { 0x60090, 1, 0x1f, 0xfff},
+       { 0x6011c, 1, 0x1f, 0xfff},
+       { 0x6012c, 1, 0x1f, 0x1fff},
+       { 0xc101c, 1, 0x1f, 0xfff},
+       { 0xc102c, 1, 0x1f, 0x1fff},
+       { 0xc2290, 1, 0x1f, 0xfff},
+       { 0xc22a0, 1, 0x1f, 0xfff},
+       { 0xc22b0, 1, 0x1f, 0x1fff},
+       { 0xc2548, 1, 0x1f, 0xfff},
+       { 0xc2550, 1, 0x1f, 0xfff},
+       { 0xc2558, 1, 0x1f, 0xfff},
+       { 0xc4294, 1, 0x1f, 0xfff},
+       { 0xc42a4, 1, 0x1f, 0xfff},
+       { 0xc42b4, 1, 0x1f, 0x1fff},
+       { 0xc4550, 1, 0x1f, 0xfff},
+       { 0xc4558, 1, 0x1f, 0xfff},
+       { 0xc4560, 1, 0x1f, 0xfff},
+       { 0xd016c, 8, 0x1f, 0xfff},
+       { 0xd01d8, 1, 0x1f, 0xfff},
+       { 0xd01e8, 1, 0x1f, 0x1fff},
+       { 0xd0204, 1, 0x1f, 0xfff},
+       { 0xd020c, 3, 0x1f, 0xfff},
+       { 0xe0154, 8, 0x1f, 0xfff},
+       { 0xe01c8, 1, 0x1f, 0xfff},
+       { 0xe01d8, 1, 0x1f, 0x1fff},
+       { 0xe0204, 1, 0x1f, 0xfff},
+       { 0xe020c, 2, 0x1f, 0xfff},
+       { 0xe021c, 2, 0x1f, 0xfff},
+       { 0x101014, 1, 0x1f, 0xfff},
+       { 0x101030, 1, 0x1f, 0xfff},
+       { 0x101040, 1, 0x1f, 0x1fff},
+       { 0x102058, 1, 0x1f, 0x1fff},
+       { 0x102080, 16, 0x1f, 0xfff},
+       { 0x103004, 2, 0x1f, 0xfff},
+       { 0x103068, 1, 0x1f, 0xfff},
+       { 0x103078, 1, 0x1f, 0xfff},
+       { 0x103088, 1, 0x1f, 0x1fff},
+       { 0x10309c, 2, 0x1e, 0xfff},
+       { 0x1030b8, 2, 0x1c, 0xfff},
+       { 0x1030cc, 1, 0x1c, 0xfff},
+       { 0x1030e0, 1, 0x1c, 0xfff},
+       { 0x104004, 1, 0x1f, 0xfff},
+       { 0x104018, 1, 0x1f, 0xfff},
+       { 0x104020, 1, 0x1f, 0xfff},
+       { 0x10403c, 1, 0x1f, 0xfff},
+       { 0x1040fc, 1, 0x1f, 0xfff},
+       { 0x10410c, 1, 0x1f, 0x1fff},
+       { 0x104400, 1, 0x1f, 0x1fff},
+       { 0x104404, 63, 0x1f, 0xfff},
+       { 0x104800, 1, 0x1f, 0x1fff},
+       { 0x104804, 63, 0x1f, 0xfff},
+       { 0x105000, 4, 0x1f, 0x1fff},
+       { 0x105010, 252, 0x1f, 0xfff},
+       { 0x108094, 1, 0x3, 0xfff},
+       { 0x1201b0, 2, 0x1f, 0xfff},
+       { 0x12032c, 1, 0x1f, 0xfff},
+       { 0x12036c, 3, 0x1f, 0xfff},
+       { 0x120408, 2, 0x1f, 0xfff},
+       { 0x120414, 15, 0x1f, 0xfff},
+       { 0x120478, 2, 0x1f, 0xfff},
+       { 0x12052c, 1, 0x1f, 0xfff},
+       { 0x120564, 3, 0x1f, 0xfff},
+       { 0x12057c, 1, 0x1f, 0x1fff},
+       { 0x12058c, 1, 0x1f, 0x1fff},
+       { 0x120608, 1, 0x1e, 0xfff},
+       { 0x120748, 1, 0x1c, 0xfff},
+       { 0x120778, 2, 0x1c, 0xfff},
+       { 0x120808, 3, 0x1f, 0xfff},
+       { 0x120818, 1, 0x1f, 0xfff},
+       { 0x120820, 1, 0x1f, 0xfff},
+       { 0x120828, 1, 0x1f, 0xfff},
+       { 0x120830, 1, 0x1f, 0xfff},
+       { 0x120838, 1, 0x1f, 0xfff},
+       { 0x120840, 1, 0x1f, 0xfff},
+       { 0x120848, 1, 0x1f, 0xfff},
+       { 0x120850, 1, 0x1f, 0xfff},
+       { 0x120858, 1, 0x1f, 0xfff},
+       { 0x120860, 1, 0x1f, 0xfff},
+       { 0x120868, 1, 0x1f, 0xfff},
+       { 0x120870, 1, 0x1f, 0xfff},
+       { 0x120878, 1, 0x1f, 0xfff},
+       { 0x120880, 1, 0x1f, 0xfff},
+       { 0x120888, 1, 0x1f, 0xfff},
+       { 0x120890, 1, 0x1f, 0xfff},
+       { 0x120898, 1, 0x1f, 0xfff},
+       { 0x1208a0, 1, 0x1f, 0xfff},
+       { 0x1208a8, 1, 0x1f, 0xfff},
+       { 0x1208b0, 1, 0x1f, 0xfff},
+       { 0x1208b8, 1, 0x1f, 0xfff},
+       { 0x1208c0, 1, 0x1f, 0xfff},
+       { 0x1208c8, 1, 0x1f, 0xfff},
+       { 0x1208d0, 1, 0x1f, 0xfff},
+       { 0x1208d8, 1, 0x1f, 0xfff},
+       { 0x1208e0, 1, 0x1f, 0xfff},
+       { 0x1208e8, 1, 0x1f, 0xfff},
+       { 0x1208f0, 1, 0x1f, 0xfff},
+       { 0x1208f8, 1, 0x1f, 0xfff},
+       { 0x120900, 1, 0x1f, 0xfff},
+       { 0x120908, 1, 0x1f, 0xfff},
+       { 0x130030, 1, 0x1c, 0xfff},
+       { 0x13004c, 3, 0x1c, 0xfff},
+       { 0x130064, 2, 0x1c, 0xfff},
+       { 0x13009c, 1, 0x1c, 0x1fff},
+       { 0x130130, 1, 0x1c, 0xfff},
+       { 0x13016c, 1, 0x1c, 0xfff},
+       { 0x130300, 1, 0x1c, 0xfff},
+       { 0x130480, 1, 0x1c, 0xfff},
+       { 0x14005c, 2, 0xf, 0xfff},
+       { 0x1400d0, 2, 0xf, 0xfff},
+       { 0x1400e0, 1, 0xf, 0xfff},
+       { 0x1401c8, 1, 0xf, 0xfff},
+       { 0x140200, 6, 0xf, 0xfff},
+       { 0x140338, 7, 0x10, 0xfff},
+       { 0x140370, 7, 0x10, 0xfff},
+       { 0x15c1bc, 6, 0x10, 0xfff},
+       { 0x15c230, 7, 0x10, 0xfff},
+       { 0x16101c, 1, 0x1f, 0xfff},
+       { 0x16102c, 1, 0x1f, 0x1fff},
+       { 0x164014, 2, 0x1f, 0xfff},
+       { 0x1640f0, 1, 0x1f, 0xfff},
+       { 0x166290, 1, 0x1f, 0xfff},
+       { 0x1662a0, 1, 0x1f, 0xfff},
+       { 0x1662b0, 1, 0x1f, 0x1fff},
+       { 0x166548, 1, 0x1f, 0xfff},
+       { 0x166550, 1, 0x1f, 0xfff},
+       { 0x166558, 1, 0x1f, 0xfff},
+       { 0x168000, 1, 0x1f, 0xfff},
+       { 0x168008, 1, 0x1f, 0xfff},
+       { 0x168010, 1, 0x1f, 0xfff},
+       { 0x168018, 1, 0x1f, 0xfff},
+       { 0x168028, 2, 0x1f, 0xfff},
+       { 0x168058, 9, 0x1f, 0xfff},
+       { 0x168238, 1, 0x1f, 0xfff},
+       { 0x1682d0, 7, 0x1f, 0xfff},
+       { 0x168300, 2, 0x3, 0xfff},
+       { 0x168308, 65, 0x1f, 0xfff},
+       { 0x168410, 2, 0x1f, 0xfff},
+       { 0x168438, 1, 0x1f, 0xfff},
+       { 0x168448, 1, 0x1f, 0x1fff},
+       { 0x168a00, 128, 0x1f, 0xfff},
+       { 0x16e200, 128, 0x2, 0xfff},
+       { 0x16e404, 2, 0x2, 0xfff},
+       { 0x16e584, 64, 0x2, 0xfff},
+       { 0x16e684, 2, 0x1e, 0xfff},
+       { 0x16e68c, 4, 0x2, 0xfff},
+       { 0x16e6fc, 4, 0x1c, 0xfff},
+       { 0x16e7ac, 12, 0x10, 0xfff},
+       { 0x1700a4, 1, 0x1f, 0xfff},
+       { 0x1700ac, 2, 0x1f, 0xfff},
+       { 0x1700c0, 1, 0x1f, 0xfff},
+       { 0x170174, 1, 0x1f, 0xfff},
+       { 0x170184, 1, 0x1f, 0x1fff},
+       { 0x1800f4, 1, 0x1f, 0xfff},
+       { 0x180104, 1, 0x1f, 0xfff},
+       { 0x180114, 1, 0x1f, 0x1fff},
+       { 0x180124, 1, 0x1f, 0x1fff},
+       { 0x18026c, 1, 0x1f, 0xfff},
+       { 0x1802a0, 1, 0x1f, 0xfff},
+       { 0x1b8000, 1, 0x1f, 0xfff},
+       { 0x1b8040, 1, 0x1f, 0xfff},
+       { 0x1b8080, 1, 0x1f, 0xfff},
+       { 0x1b80c0, 1, 0x1f, 0xfff},
+       { 0x200104, 1, 0x1f, 0xfff},
+       { 0x200114, 1, 0x1f, 0xfff},
+       { 0x200124, 1, 0x1f, 0x1fff},
+       { 0x200134, 1, 0x1f, 0x1fff},
+       { 0x20026c, 1, 0x1f, 0xfff},
+       { 0x2002a0, 1, 0x1f, 0xfff},
+       { 0x238000, 1, 0x1f, 0xfff},
+       { 0x238040, 1, 0x1f, 0xfff},
+       { 0x238080, 1, 0x1f, 0xfff},
+       { 0x2380c0, 1, 0x1f, 0xfff},
+       { 0x280104, 1, 0x1f, 0xfff},
+       { 0x280114, 1, 0x1f, 0xfff},
+       { 0x280124, 1, 0x1f, 0x1fff},
+       { 0x280134, 1, 0x1f, 0x1fff},
+       { 0x28026c, 1, 0x1f, 0xfff},
+       { 0x2802a0, 1, 0x1f, 0xfff},
+       { 0x2b8000, 1, 0x1f, 0xfff},
+       { 0x2b8040, 1, 0x1f, 0xfff},
+       { 0x2b8080, 1, 0x1f, 0xfff},
+       { 0x300104, 1, 0x1f, 0xfff},
+       { 0x300114, 1, 0x1f, 0xfff},
+       { 0x300124, 1, 0x1f, 0x1fff},
+       { 0x300134, 1, 0x1f, 0x1fff},
+       { 0x30026c, 1, 0x1f, 0xfff},
+       { 0x3002a0, 1, 0x1f, 0xfff},
+       { 0x338000, 1, 0x1f, 0xfff},
+       { 0x338040, 1, 0x1f, 0xfff},
+       { 0x338080, 1, 0x1f, 0xfff},
+       { 0x3380c0, 1, 0x1f, 0xfff}
+};
 
-static const u32 page_write_regs_e2[] = { 328476 };
-#define PAGE_WRITE_REGS_E2             ARRAY_SIZE(page_write_regs_e2)
+#define IDLE_REGS_COUNT ARRAY_SIZE(idle_reg_addrs)
 
-static const struct reg_addr page_read_regs_e2[] = {
-       { 0x58000, 4608, RI_E2_ONLINE } };
-#define PAGE_READ_REGS_E2              ARRAY_SIZE(page_read_regs_e2)
+static const u32 read_reg_e1[] = {
+       0x1b1000};
 
-static const u32 page_vals_e3[] = { 0, 128 };
-#define PAGE_MODE_VALUES_E3            ARRAY_SIZE(page_vals_e3)
+static const struct wreg_addr wreg_addr_e1 = {
+       0x1b0c00, 192, 1, read_reg_e1, 0x1f, 0x1fff};
 
-static const u32 page_write_regs_e3[] = { 328476 };
-#define PAGE_WRITE_REGS_E3             ARRAY_SIZE(page_write_regs_e3)
+static const u32 read_reg_e1h[] = {
+       0x1b1040, 0x1b1000};
 
-static const struct reg_addr page_read_regs_e3[] = {
-       { 0x58000, 4608, RI_E3E3B0_ONLINE } };
-#define PAGE_READ_REGS_E3              ARRAY_SIZE(page_read_regs_e3)
+static const struct wreg_addr wreg_addr_e1h = {
+       0x1b0c00, 256, 2, read_reg_e1h, 0x1f, 0x1fff};
+
+static const u32 read_reg_e2[] = {
+       0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e2 = {
+       0x1b0c00, 128, 2, read_reg_e2, 0x1f, 0x1fff};
 
-#endif /* BNX2X_DUMP_H */
+static const u32 read_reg_e3[] = {
+       0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e3 = {
+       0x1b0c00, 128, 2, read_reg_e3, 0x1f, 0x1fff};
+
+static const u32 read_reg_e3b0[] = {
+       0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e3b0 = {
+       0x1b0c00, 128, 2, read_reg_e3b0, 0x1f, 0x1fff};
+
+static const unsigned int dump_num_registers[NUM_CHIPS][NUM_PRESETS] = {
+       {20782, 18567, 27975, 19729, 18311, 27719, 20836, 32391, 41799, 20812,
+        26247, 35655, 19074},
+       {32774, 19297, 33277, 31721, 19041, 33021, 32828, 33121, 47101, 32804,
+        26977, 40957, 35895},
+       {36527, 17928, 33697, 35474, 18700, 34466, 36581, 31752, 47521, 36557,
+        25608, 41377, 43903},
+       {45239, 17936, 34387, 44186, 18708, 35156, 45293, 31760, 48211, 45269,
+        25616, 42067, 43903},
+       {45302, 17999, 34802, 44249, 18771, 35571, 45356, 31823, 48626, 45332,
+        25679, 42482, 43903}
+};
+#endif
index a427b49a886ccea8a6d904daa473a59f5a676c5b..9a674b14b403dc605bfb10c448ea8a175a2614ae 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_ethtool.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -186,6 +186,7 @@ static const struct {
 };
 
 #define BNX2X_NUM_STATS                ARRAY_SIZE(bnx2x_stats_arr)
+
 static int bnx2x_get_port_type(struct bnx2x *bp)
 {
        int port_type;
@@ -233,7 +234,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
        if ((bp->state == BNX2X_STATE_OPEN) && bp->link_vars.link_up &&
            !(bp->flags & MF_FUNC_DIS)) {
-                       cmd->duplex = bp->link_vars.duplex;
+               cmd->duplex = bp->link_vars.duplex;
 
                if (IS_MF(bp) && !BP_NOMCP(bp))
                        ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp));
@@ -399,7 +400,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                DP(BNX2X_MSG_ETHTOOL, "Unsupported port type\n");
                return -EINVAL;
        }
-       /* Save new config in case command complete successully */
+       /* Save new config in case command complete successfully */
        new_multi_phy_config = bp->link_params.multi_phy_config;
        /* Get the new cfg_idx */
        cfg_idx = bnx2x_get_link_cfg_idx(bp);
@@ -596,29 +597,58 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        return 0;
 }
 
-#define IS_E1_ONLINE(info)     (((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
-#define IS_E1H_ONLINE(info)    (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
-#define IS_E2_ONLINE(info)     (((info) & RI_E2_ONLINE) == RI_E2_ONLINE)
-#define IS_E3_ONLINE(info)     (((info) & RI_E3_ONLINE) == RI_E3_ONLINE)
-#define IS_E3B0_ONLINE(info)   (((info) & RI_E3B0_ONLINE) == RI_E3B0_ONLINE)
+#define DUMP_ALL_PRESETS               0x1FFF
+#define DUMP_MAX_PRESETS               13
 
-static bool bnx2x_is_reg_online(struct bnx2x *bp,
-                               const struct reg_addr *reg_info)
+static int __bnx2x_get_preset_regs_len(struct bnx2x *bp, u32 preset)
 {
        if (CHIP_IS_E1(bp))
-               return IS_E1_ONLINE(reg_info->info);
+               return dump_num_registers[0][preset-1];
        else if (CHIP_IS_E1H(bp))
-               return IS_E1H_ONLINE(reg_info->info);
+               return dump_num_registers[1][preset-1];
        else if (CHIP_IS_E2(bp))
-               return IS_E2_ONLINE(reg_info->info);
+               return dump_num_registers[2][preset-1];
        else if (CHIP_IS_E3A0(bp))
-               return IS_E3_ONLINE(reg_info->info);
+               return dump_num_registers[3][preset-1];
        else if (CHIP_IS_E3B0(bp))
-               return IS_E3B0_ONLINE(reg_info->info);
+               return dump_num_registers[4][preset-1];
        else
-               return false;
+               return 0;
+}
+
+static int __bnx2x_get_regs_len(struct bnx2x *bp)
+{
+       u32 preset_idx;
+       int regdump_len = 0;
+
+       /* Calculate the total preset regs length */
+       for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++)
+               regdump_len += __bnx2x_get_preset_regs_len(bp, preset_idx);
+
+       return regdump_len;
+}
+
+static int bnx2x_get_regs_len(struct net_device *dev)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       int regdump_len = 0;
+
+       regdump_len = __bnx2x_get_regs_len(bp);
+       regdump_len *= 4;
+       regdump_len += sizeof(struct dump_header);
+
+       return regdump_len;
 }
 
+#define IS_E1_REG(chips)       ((chips & DUMP_CHIP_E1) == DUMP_CHIP_E1)
+#define IS_E1H_REG(chips)      ((chips & DUMP_CHIP_E1H) == DUMP_CHIP_E1H)
+#define IS_E2_REG(chips)       ((chips & DUMP_CHIP_E2) == DUMP_CHIP_E2)
+#define IS_E3A0_REG(chips)     ((chips & DUMP_CHIP_E3A0) == DUMP_CHIP_E3A0)
+#define IS_E3B0_REG(chips)     ((chips & DUMP_CHIP_E3B0) == DUMP_CHIP_E3B0)
+
+#define IS_REG_IN_PRESET(presets, idx)  \
+               ((presets & (1 << (idx-1))) == (1 << (idx-1)))
+
 /******* Paged registers info selectors ********/
 static const u32 *__bnx2x_get_page_addr_ar(struct bnx2x *bp)
 {
@@ -680,38 +710,39 @@ static u32 __bnx2x_get_page_read_num(struct bnx2x *bp)
                return 0;
 }
 
-static int __bnx2x_get_regs_len(struct bnx2x *bp)
+static bool bnx2x_is_reg_in_chip(struct bnx2x *bp,
+                                      const struct reg_addr *reg_info)
 {
-       int num_pages = __bnx2x_get_page_reg_num(bp);
-       int page_write_num = __bnx2x_get_page_write_num(bp);
-       const struct reg_addr *page_read_addr = __bnx2x_get_page_read_ar(bp);
-       int page_read_num = __bnx2x_get_page_read_num(bp);
-       int regdump_len = 0;
-       int i, j, k;
-
-       for (i = 0; i < REGS_COUNT; i++)
-               if (bnx2x_is_reg_online(bp, &reg_addrs[i]))
-                       regdump_len += reg_addrs[i].size;
-
-       for (i = 0; i < num_pages; i++)
-               for (j = 0; j < page_write_num; j++)
-                       for (k = 0; k < page_read_num; k++)
-                               if (bnx2x_is_reg_online(bp, &page_read_addr[k]))
-                                       regdump_len += page_read_addr[k].size;
-
-       return regdump_len;
+       if (CHIP_IS_E1(bp))
+               return IS_E1_REG(reg_info->chips);
+       else if (CHIP_IS_E1H(bp))
+               return IS_E1H_REG(reg_info->chips);
+       else if (CHIP_IS_E2(bp))
+               return IS_E2_REG(reg_info->chips);
+       else if (CHIP_IS_E3A0(bp))
+               return IS_E3A0_REG(reg_info->chips);
+       else if (CHIP_IS_E3B0(bp))
+               return IS_E3B0_REG(reg_info->chips);
+       else
+               return false;
 }
 
-static int bnx2x_get_regs_len(struct net_device *dev)
-{
-       struct bnx2x *bp = netdev_priv(dev);
-       int regdump_len = 0;
 
-       regdump_len = __bnx2x_get_regs_len(bp);
-       regdump_len *= 4;
-       regdump_len += sizeof(struct dump_hdr);
-
-       return regdump_len;
+static bool bnx2x_is_wreg_in_chip(struct bnx2x *bp,
+       const struct wreg_addr *wreg_info)
+{
+       if (CHIP_IS_E1(bp))
+               return IS_E1_REG(wreg_info->chips);
+       else if (CHIP_IS_E1H(bp))
+               return IS_E1H_REG(wreg_info->chips);
+       else if (CHIP_IS_E2(bp))
+               return IS_E2_REG(wreg_info->chips);
+       else if (CHIP_IS_E3A0(bp))
+               return IS_E3A0_REG(wreg_info->chips);
+       else if (CHIP_IS_E3B0(bp))
+               return IS_E3B0_REG(wreg_info->chips);
+       else
+               return false;
 }
 
 /**
@@ -725,9 +756,10 @@ static int bnx2x_get_regs_len(struct net_device *dev)
  * ("read address"). There may be more than one write address per "page" and
  * more than one read address per write address.
  */
-static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p)
+static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p, u32 preset)
 {
        u32 i, j, k, n;
+
        /* addresses of the paged registers */
        const u32 *page_addr = __bnx2x_get_page_addr_ar(bp);
        /* number of paged registers */
@@ -740,32 +772,100 @@ static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p)
        const struct reg_addr *read_addr = __bnx2x_get_page_read_ar(bp);
        /* number of read addresses */
        int read_num = __bnx2x_get_page_read_num(bp);
+       u32 addr, size;
 
        for (i = 0; i < num_pages; i++) {
                for (j = 0; j < write_num; j++) {
                        REG_WR(bp, write_addr[j], page_addr[i]);
-                       for (k = 0; k < read_num; k++)
-                               if (bnx2x_is_reg_online(bp, &read_addr[k]))
-                                       for (n = 0; n <
-                                             read_addr[k].size; n++)
-                                               *p++ = REG_RD(bp,
-                                                      read_addr[k].addr + n*4);
+
+                       for (k = 0; k < read_num; k++) {
+                               if (IS_REG_IN_PRESET(read_addr[k].presets,
+                                                    preset)) {
+                                       size = read_addr[k].size;
+                                       for (n = 0; n < size; n++) {
+                                               addr = read_addr[k].addr + n*4;
+                                               *p++ = REG_RD(bp, addr);
+                                       }
+                               }
+                       }
                }
        }
 }
 
-static void __bnx2x_get_regs(struct bnx2x *bp, u32 *p)
+static int __bnx2x_get_preset_regs(struct bnx2x *bp, u32 *p, u32 preset)
 {
-       u32 i, j;
+       u32 i, j, addr;
+       const struct wreg_addr *wreg_addr_p = NULL;
+
+       if (CHIP_IS_E1(bp))
+               wreg_addr_p = &wreg_addr_e1;
+       else if (CHIP_IS_E1H(bp))
+               wreg_addr_p = &wreg_addr_e1h;
+       else if (CHIP_IS_E2(bp))
+               wreg_addr_p = &wreg_addr_e2;
+       else if (CHIP_IS_E3A0(bp))
+               wreg_addr_p = &wreg_addr_e3;
+       else if (CHIP_IS_E3B0(bp))
+               wreg_addr_p = &wreg_addr_e3b0;
+
+       /* Read the idle_chk registers */
+       for (i = 0; i < IDLE_REGS_COUNT; i++) {
+               if (bnx2x_is_reg_in_chip(bp, &idle_reg_addrs[i]) &&
+                   IS_REG_IN_PRESET(idle_reg_addrs[i].presets, preset)) {
+                       for (j = 0; j < idle_reg_addrs[i].size; j++)
+                               *p++ = REG_RD(bp, idle_reg_addrs[i].addr + j*4);
+               }
+       }
 
        /* Read the regular registers */
-       for (i = 0; i < REGS_COUNT; i++)
-               if (bnx2x_is_reg_online(bp, &reg_addrs[i]))
+       for (i = 0; i < REGS_COUNT; i++) {
+               if (bnx2x_is_reg_in_chip(bp, &reg_addrs[i]) &&
+                   IS_REG_IN_PRESET(reg_addrs[i].presets, preset)) {
                        for (j = 0; j < reg_addrs[i].size; j++)
                                *p++ = REG_RD(bp, reg_addrs[i].addr + j*4);
+               }
+       }
+
+       /* Read the CAM registers */
+       if (bnx2x_is_wreg_in_chip(bp, wreg_addr_p) &&
+           IS_REG_IN_PRESET(wreg_addr_p->presets, preset)) {
+               for (i = 0; i < wreg_addr_p->size; i++) {
+                       *p++ = REG_RD(bp, wreg_addr_p->addr + i*4);
 
-       /* Read "paged" registes */
-       bnx2x_read_pages_regs(bp, p);
+                       /* In case of wreg_addr register, read additional
+                          registers from read_regs array
+                       */
+                       for (j = 0; j < wreg_addr_p->read_regs_count; j++) {
+                               addr = *(wreg_addr_p->read_regs);
+                               *p++ = REG_RD(bp, addr + j*4);
+                       }
+               }
+       }
+
+       /* Paged registers are supported in E2 & E3 only */
+       if (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) {
+               /* Read "paged" registes */
+               bnx2x_read_pages_regs(bp, p, preset);
+       }
+
+       return 0;
+}
+
+static void __bnx2x_get_regs(struct bnx2x *bp, u32 *p)
+{
+       u32 preset_idx;
+
+       /* Read all registers, by reading all preset registers */
+       for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++) {
+               /* Skip presets with IOR */
+               if ((preset_idx == 2) ||
+                   (preset_idx == 5) ||
+                   (preset_idx == 8) ||
+                   (preset_idx == 11))
+                       continue;
+               __bnx2x_get_preset_regs(bp, p, preset_idx);
+               p += __bnx2x_get_preset_regs_len(bp, preset_idx);
+       }
 }
 
 static void bnx2x_get_regs(struct net_device *dev,
@@ -773,9 +873,9 @@ static void bnx2x_get_regs(struct net_device *dev,
 {
        u32 *p = _p;
        struct bnx2x *bp = netdev_priv(dev);
-       struct dump_hdr dump_hdr = {0};
+       struct dump_header dump_hdr = {0};
 
-       regs->version = 1;
+       regs->version = 2;
        memset(p, 0, regs->len);
 
        if (!netif_running(bp->dev))
@@ -785,53 +885,173 @@ static void bnx2x_get_regs(struct net_device *dev,
         * cause false alarms by reading never written registers. We
         * will re-enable parity attentions right after the dump.
         */
+
+       /* Disable parity on path 0 */
+       bnx2x_pretend_func(bp, 0);
        bnx2x_disable_blocks_parity(bp);
 
-       dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
-       dump_hdr.dump_sign = dump_sign_all;
-       dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
-       dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
-       dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
-       dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
+       /* Disable parity on path 1 */
+       bnx2x_pretend_func(bp, 1);
+       bnx2x_disable_blocks_parity(bp);
 
-       if (CHIP_IS_E1(bp))
-               dump_hdr.info = RI_E1_ONLINE;
-       else if (CHIP_IS_E1H(bp))
-               dump_hdr.info = RI_E1H_ONLINE;
-       else if (!CHIP_IS_E1x(bp))
-               dump_hdr.info = RI_E2_ONLINE |
-               (BP_PATH(bp) ? RI_PATH1_DUMP : RI_PATH0_DUMP);
+       /* Return to current function */
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+       dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
+       dump_hdr.preset = DUMP_ALL_PRESETS;
+       dump_hdr.version = BNX2X_DUMP_VERSION;
+
+       /* dump_meta_data presents OR of CHIP and PATH. */
+       if (CHIP_IS_E1(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E1;
+       } else if (CHIP_IS_E1H(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E1H;
+       } else if (CHIP_IS_E2(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E2 |
+               (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+       } else if (CHIP_IS_E3A0(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 |
+               (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+       } else if (CHIP_IS_E3B0(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 |
+               (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+       }
 
-       memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
-       p += dump_hdr.hdr_size + 1;
+       memcpy(p, &dump_hdr, sizeof(struct dump_header));
+       p += dump_hdr.header_size + 1;
 
        /* Actually read the registers */
        __bnx2x_get_regs(bp, p);
 
-       /* Re-enable parity attentions */
+       /* Re-enable parity attentions on path 0 */
+       bnx2x_pretend_func(bp, 0);
        bnx2x_clear_blocks_parity(bp);
        bnx2x_enable_blocks_parity(bp);
+
+       /* Re-enable parity attentions on path 1 */
+       bnx2x_pretend_func(bp, 1);
+       bnx2x_clear_blocks_parity(bp);
+       bnx2x_enable_blocks_parity(bp);
+
+       /* Return to current function */
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static int bnx2x_get_preset_regs_len(struct net_device *dev, u32 preset)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       int regdump_len = 0;
+
+       regdump_len = __bnx2x_get_preset_regs_len(bp, preset);
+       regdump_len *= 4;
+       regdump_len += sizeof(struct dump_header);
+
+       return regdump_len;
+}
+
+static int bnx2x_set_dump(struct net_device *dev, struct ethtool_dump *val)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+
+       /* Use the ethtool_dump "flag" field as the dump preset index */
+       bp->dump_preset_idx = val->flag;
+       return 0;
+}
+
+static int bnx2x_get_dump_flag(struct net_device *dev,
+                              struct ethtool_dump *dump)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+
+       /* Calculate the requested preset idx length */
+       dump->len = bnx2x_get_preset_regs_len(dev, bp->dump_preset_idx);
+       DP(BNX2X_MSG_ETHTOOL, "Get dump preset %d length=%d\n",
+          bp->dump_preset_idx, dump->len);
+
+       dump->flag = ETHTOOL_GET_DUMP_DATA;
+       return 0;
+}
+
+static int bnx2x_get_dump_data(struct net_device *dev,
+                              struct ethtool_dump *dump,
+                              void *buffer)
+{
+       u32 *p = buffer;
+       struct bnx2x *bp = netdev_priv(dev);
+       struct dump_header dump_hdr = {0};
+
+       memset(p, 0, dump->len);
+
+       /* Disable parity attentions as long as following dump may
+        * cause false alarms by reading never written registers. We
+        * will re-enable parity attentions right after the dump.
+        */
+
+       /* Disable parity on path 0 */
+       bnx2x_pretend_func(bp, 0);
+       bnx2x_disable_blocks_parity(bp);
+
+       /* Disable parity on path 1 */
+       bnx2x_pretend_func(bp, 1);
+       bnx2x_disable_blocks_parity(bp);
+
+       /* Return to current function */
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+       dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
+       dump_hdr.preset = bp->dump_preset_idx;
+       dump_hdr.version = BNX2X_DUMP_VERSION;
+
+       DP(BNX2X_MSG_ETHTOOL, "Get dump data of preset %d\n", dump_hdr.preset);
+
+       /* dump_meta_data presents OR of CHIP and PATH. */
+       if (CHIP_IS_E1(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E1;
+       } else if (CHIP_IS_E1H(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E1H;
+       } else if (CHIP_IS_E2(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E2 |
+               (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+       } else if (CHIP_IS_E3A0(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 |
+               (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+       } else if (CHIP_IS_E3B0(bp)) {
+               dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 |
+               (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+       }
+
+       memcpy(p, &dump_hdr, sizeof(struct dump_header));
+       p += dump_hdr.header_size + 1;
+
+       /* Actually read the registers */
+       __bnx2x_get_preset_regs(bp, p, dump_hdr.preset);
+
+       /* Re-enable parity attentions on path 0 */
+       bnx2x_pretend_func(bp, 0);
+       bnx2x_clear_blocks_parity(bp);
+       bnx2x_enable_blocks_parity(bp);
+
+       /* Re-enable parity attentions on path 1 */
+       bnx2x_pretend_func(bp, 1);
+       bnx2x_clear_blocks_parity(bp);
+       bnx2x_enable_blocks_parity(bp);
+
+       /* Return to current function */
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+       return 0;
 }
 
 static void bnx2x_get_drvinfo(struct net_device *dev,
                              struct ethtool_drvinfo *info)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       u8 phy_fw_ver[PHY_FW_VER_LEN];
 
        strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
        strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 
-       phy_fw_ver[0] = '\0';
-       bnx2x_get_ext_phy_fw_version(&bp->link_params,
-                                    phy_fw_ver, PHY_FW_VER_LEN);
-       strlcpy(info->fw_version, bp->fw_ver, sizeof(info->fw_version));
-       snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
-                "bc %d.%d.%d%s%s",
-                (bp->common.bc_ver & 0xff0000) >> 16,
-                (bp->common.bc_ver & 0xff00) >> 8,
-                (bp->common.bc_ver & 0xff),
-                ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+       bnx2x_fill_fw_str(bp, info->fw_version, sizeof(info->fw_version));
+
        strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
        info->n_stats = BNX2X_NUM_STATS;
        info->testinfo_len = BNX2X_NUM_TESTS(bp);
@@ -861,13 +1081,13 @@ static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct bnx2x *bp = netdev_priv(dev);
 
        if (wol->wolopts & ~WAKE_MAGIC) {
-               DP(BNX2X_MSG_ETHTOOL, "WOL not supproted\n");
+               DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n");
                return -EINVAL;
        }
 
        if (wol->wolopts & WAKE_MAGIC) {
                if (bp->flags & NO_WOL_FLAG) {
-                       DP(BNX2X_MSG_ETHTOOL, "WOL not supproted\n");
+                       DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n");
                        return -EINVAL;
                }
                bp->wol = 1;
@@ -890,7 +1110,7 @@ static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
 
        if (capable(CAP_NET_ADMIN)) {
                /* dump MCP trace */
-               if (level & BNX2X_MSG_MCP)
+               if (IS_PF(bp) && (level & BNX2X_MSG_MCP))
                        bnx2x_fw_dump_lvl(bp, KERN_INFO);
                bp->msg_enable = level;
        }
@@ -940,7 +1160,7 @@ static int bnx2x_get_eeprom_len(struct net_device *dev)
  * Pf B takes the lock and proceeds to perform it's own access.
  * pf A unlocks the per port lock, while pf B is still working (!).
  * mcp takes the per port lock and corrupts pf B's access (and/or has it's own
- * acess corrupted by pf B).*
+ * access corrupted by pf B)
  */
 static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
 {
@@ -1070,7 +1290,8 @@ static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val,
                        val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
                        /* we read nvram data in cpu order
                         * but ethtool sees it as an array of bytes
-                        * converting to big-endian will do the work */
+                        * converting to big-endian will do the work
+                        */
                        *ret_val = cpu_to_be32(val);
                        rc = 0;
                        break;
@@ -1297,7 +1518,8 @@ static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
                val |= (*data_buf << BYTE_OFFSET(offset));
 
                /* nvram data is returned as an array of bytes
-                * convert it back to cpu order */
+                * convert it back to cpu order
+                */
                val = be32_to_cpu(val);
 
                rc = bnx2x_nvram_write_dword(bp, align_offset, val,
@@ -1509,6 +1731,10 @@ static int bnx2x_set_ringparam(struct net_device *dev,
 {
        struct bnx2x *bp = netdev_priv(dev);
 
+       DP(BNX2X_MSG_ETHTOOL,
+          "set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
+          ering->rx_pending, ering->tx_pending);
+
        if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
                DP(BNX2X_MSG_ETHTOOL,
                   "Handling parity error recovery. Try again later\n");
@@ -1747,7 +1973,6 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata)
        return 0;
 }
 
-
 enum {
        BNX2X_CHIP_E1_OFST = 0,
        BNX2X_CHIP_E1H_OFST,
@@ -1875,7 +2100,8 @@ static int bnx2x_test_registers(struct bnx2x *bp)
                hw = BNX2X_CHIP_MASK_E3;
 
        /* Repeat the test twice:
-          First by writing 0x00000000, second by writing 0xffffffff */
+        * First by writing 0x00000000, second by writing 0xffffffff
+        */
        for (idx = 0; idx < 2; idx++) {
 
                switch (idx) {
@@ -2388,8 +2614,8 @@ static void bnx2x_self_test(struct net_device *dev,
                            struct ethtool_test *etest, u64 *buf)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       u8 is_serdes;
-       int rc;
+       u8 is_serdes, link_up;
+       int rc, cnt = 0;
 
        if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
                netdev_err(bp->dev,
@@ -2397,6 +2623,7 @@ static void bnx2x_self_test(struct net_device *dev,
                etest->flags |= ETH_TEST_FL_FAILED;
                return;
        }
+
        DP(BNX2X_MSG_ETHTOOL,
           "Self-test command parameters: offline = %d, external_lb = %d\n",
           (etest->flags & ETH_TEST_FL_OFFLINE),
@@ -2411,20 +2638,17 @@ static void bnx2x_self_test(struct net_device *dev,
        }
 
        is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0;
-
+       link_up = bp->link_vars.link_up;
        /* offline tests are not supported in MF mode */
        if ((etest->flags & ETH_TEST_FL_OFFLINE) && !IS_MF(bp)) {
                int port = BP_PORT(bp);
                u32 val;
-               u8 link_up;
 
                /* save current value of input enable for TX port IF */
                val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
                /* disable input for TX port IF */
                REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
 
-               link_up = bp->link_vars.link_up;
-
                bnx2x_nic_unload(bp, UNLOAD_NORMAL, false);
                rc = bnx2x_nic_load(bp, LOAD_DIAG);
                if (rc) {
@@ -2486,17 +2710,19 @@ static void bnx2x_self_test(struct net_device *dev,
                etest->flags |= ETH_TEST_FL_FAILED;
        }
 
-       if (bnx2x_link_test(bp, is_serdes) != 0) {
+       if (link_up) {
+               cnt = 100;
+               while (bnx2x_link_test(bp, is_serdes) && --cnt)
+                       msleep(20);
+       }
+
+       if (!cnt) {
                if (!IS_MF(bp))
                        buf[6] = 1;
                else
                        buf[2] = 1;
                etest->flags |= ETH_TEST_FL_FAILED;
        }
-
-#ifdef BNX2X_EXTRA_DEBUG
-       bnx2x_panic_dump(bp);
-#endif
 }
 
 #define IS_PORT_STAT(i) \
@@ -2753,15 +2979,14 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
                        DP(BNX2X_MSG_ETHTOOL,
                           "Command parameters not supported\n");
                        return -EINVAL;
-               } else {
-                       return 0;
                }
+               return 0;
 
        case UDP_V4_FLOW:
        case UDP_V6_FLOW:
                /* For UDP either 2-tupple hash or 4-tupple hash is supported */
                if (info->data == (RXH_IP_SRC | RXH_IP_DST |
-                                RXH_L4_B_0_1 | RXH_L4_B_2_3))
+                                  RXH_L4_B_0_1 | RXH_L4_B_2_3))
                        udp_rss_requested = 1;
                else if (info->data == (RXH_IP_SRC | RXH_IP_DST))
                        udp_rss_requested = 0;
@@ -2781,9 +3006,9 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
                           "rss re-configured, UDP 4-tupple %s\n",
                           udp_rss_requested ? "enabled" : "disabled");
                        return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
-               } else {
-                       return 0;
                }
+               return 0;
+
        case IPV4_FLOW:
        case IPV6_FLOW:
                /* For IP only 2-tupple hash is supported */
@@ -2791,9 +3016,9 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
                        DP(BNX2X_MSG_ETHTOOL,
                           "Command parameters not supported\n");
                        return -EINVAL;
-               } else {
-                       return 0;
                }
+               return 0;
+
        case SCTP_V4_FLOW:
        case AH_ESP_V4_FLOW:
        case AH_V4_FLOW:
@@ -2809,9 +3034,9 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
                        DP(BNX2X_MSG_ETHTOOL,
                           "Command parameters not supported\n");
                        return -EINVAL;
-               } else {
-                       return 0;
                }
+               return 0;
+
        default:
                return -EINVAL;
        }
@@ -2964,6 +3189,9 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
        .get_drvinfo            = bnx2x_get_drvinfo,
        .get_regs_len           = bnx2x_get_regs_len,
        .get_regs               = bnx2x_get_regs,
+       .get_dump_flag          = bnx2x_get_dump_flag,
+       .get_dump_data          = bnx2x_get_dump_data,
+       .set_dump               = bnx2x_set_dump,
        .get_wol                = bnx2x_get_wol,
        .set_wol                = bnx2x_set_wol,
        .get_msglevel           = bnx2x_get_msglevel,
index 60a83ad103700602814842e8d3f47e40386801e8..e5f808377c910cea0f578c3f3cc33cf4c91a5877 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_fw_defs.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #define MAX_VLAN_CREDIT_E1H 0 /* Per Chip */
 #define MAX_VLAN_CREDIT_E2 272 /* Per Path */
 
-
 /* Maximal aggregation queues supported */
 #define ETH_MAX_AGGREGATION_QUEUES_E1 32
 #define ETH_MAX_AGGREGATION_QUEUES_E1H_E2 64
 
-
 #define ETH_NUM_OF_MCAST_BINS 256
 #define ETH_NUM_OF_MCAST_ENGINES_E2 72
 
 /* max number of slow path commands per port */
 #define MAX_RAMRODS_PER_PORT 8
 
-
 /**** DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/
 
 #define TIMERS_TICK_SIZE_CHIP (1e-3)
        that is not mapped to priority*/
 #define LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED 0xFF
 
-
 #define C_ERES_PER_PAGE \
        (PAGE_SIZE / BITS_TO_BYTES(STRUCT_SIZE(event_ring_elem)))
 #define C_ERE_PER_PAGE_MASK (C_ERES_PER_PAGE - 1)
 
 #define INVALID_VNIC_ID        0xFF
 
-
 #define UNDEF_IRO 0x80000000
 
-
 #endif /* BNX2X_FW_DEFS_H */
index 4bed52ba300d4acbe466b4f0930f2fc5c7993e74..f572ae164fce4d49317ca752e2cd0eaac1895ae3 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_fw_file_hdr.h: FW binary file header structure.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index 3369a50ac6b4fbe087860883c9dd9afc951c3238..037860ecc3434cffca9ee555846ae21dbe8600ab 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_hsi.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -899,6 +899,10 @@ struct port_feat_cfg {                 /* port 0: 0x454  port 1: 0x4c8 */
                #define PORT_FEAT_CFG_DCBX_DISABLED                  0x00000000
                #define PORT_FEAT_CFG_DCBX_ENABLED                   0x00000100
 
+               #define PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK        0x00000C00
+               #define PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE        0x00000400
+               #define PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI       0x00000800
+
        #define PORT_FEATURE_EN_SIZE_MASK                   0x0f000000
        #define PORT_FEATURE_EN_SIZE_SHIFT                           24
        #define PORT_FEATURE_WOL_ENABLED                             0x01000000
@@ -3374,6 +3378,10 @@ struct regpair {
        __le32 hi;
 };
 
+struct regpair_native {
+       u32 lo;
+       u32 hi;
+};
 
 /*
  * Classify rule opcodes in E2/E3
@@ -4400,13 +4408,13 @@ struct tstorm_eth_function_common_config {
  * MAC filtering configuration parameters per port in Tstorm
  */
 struct tstorm_eth_mac_filter_config {
-       __le32 ucast_drop_all;
-       __le32 ucast_accept_all;
-       __le32 mcast_drop_all;
-       __le32 mcast_accept_all;
-       __le32 bcast_accept_all;
-       __le32 vlan_filter[2];
-       __le32 unmatched_unicast;
+       u32 ucast_drop_all;
+       u32 ucast_accept_all;
+       u32 mcast_drop_all;
+       u32 mcast_accept_all;
+       u32 bcast_accept_all;
+       u32 vlan_filter[2];
+       u32 unmatched_unicast;
 };
 
 
@@ -4898,7 +4906,7 @@ union event_data {
  * per PF event ring data
  */
 struct event_ring_data {
-       struct regpair base_addr;
+       struct regpair_native base_addr;
 #if defined(__BIG_ENDIAN)
        u8 index_id;
        u8 sb_id;
@@ -5131,7 +5139,7 @@ struct pci_entity {
  * The fast-path status block meta-data, common to all chips
  */
 struct hc_sb_data {
-       struct regpair host_sb_addr;
+       struct regpair_native host_sb_addr;
        struct hc_status_block_sm state_machine[HC_SB_MAX_SM];
        struct pci_entity p_func;
 #if defined(__BIG_ENDIAN)
@@ -5145,7 +5153,7 @@ struct hc_sb_data {
        u8 state;
        u8 rsrv0;
 #endif
-       struct regpair rsrv1[2];
+       struct regpair_native rsrv1[2];
 };
 
 
@@ -5163,7 +5171,7 @@ enum hc_segment {
  * The fast-path status block meta-data
  */
 struct hc_sp_status_block_data {
-       struct regpair host_sb_addr;
+       struct regpair_native host_sb_addr;
 #if defined(__BIG_ENDIAN)
        u8 rsrv1;
        u8 state;
index c8f10f0e8a0dea6db58e412989f2d35eddc6528d..76df015f486ad9d1653efccde3538dbb47263849 100644 (file)
@@ -1,7 +1,7 @@
 /* bnx2x_init.h: Broadcom Everest network driver.
  *               Structures and macroes needed during the initialization.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index d755acfe7a4076d71a5f03d6fcdd491c12d53cba..8ab0dd90096085b33f4ee831f6487c3766b164af 100644 (file)
@@ -2,7 +2,7 @@
  *               Static functions needed during the initialization.
  *               This file is "included" in bnx2x_main.c.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -218,7 +218,7 @@ static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, u32 len,
        /* gunzip_outlen is in dwords */
        len = GUNZIP_OUTLEN(bp);
        for (i = 0; i < len; i++)
-               ((u32 *)GUNZIP_BUF(bp))[i] =
+               ((u32 *)GUNZIP_BUF(bp))[i] = (__force u32)
                                cpu_to_le32(((u32 *)GUNZIP_BUF(bp))[i]);
 
        bnx2x_write_big_buf_wb(bp, addr, len);
@@ -232,7 +232,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage)
        u16 op_end =
                INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage,
                                                     STAGE_END)];
-       union init_op *op;
+       const union init_op *op;
        u32 op_idx, op_type, addr, len;
        const u32 *data, *data_base;
 
@@ -244,7 +244,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage)
 
        for (op_idx = op_start; op_idx < op_end; op_idx++) {
 
-               op = (union init_op *)&(INIT_OPS(bp)[op_idx]);
+               op = (const union init_op *)&(INIT_OPS(bp)[op_idx]);
                /* Get generic data */
                op_type = op->raw.op;
                addr = op->raw.offset;
index 09096b43a6e9f7da5a9304093da121fe2e7aeb12..859df751345e6f9707ca1a402d95cf9685a37419 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2008-2012 Broadcom Corporation
+/* Copyright 2008-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -3659,7 +3659,7 @@ static void bnx2x_warpcore_enable_AN_KR2(struct bnx2x_phy *phy,
        bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
                                 MDIO_WC_REG_CL49_USERB0_CTRL, (3<<6));
 
-       for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
 
@@ -3713,7 +3713,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        };
        DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
        /* Set to default registers that may be overriden by 10G force */
-       for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
 
@@ -3854,7 +3854,7 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
                {MDIO_PMA_DEVAD, MDIO_WC_REG_PMD_KR_CONTROL, 0x2}
        };
 
-       for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
 
@@ -4242,7 +4242,7 @@ static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy,
        bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
                                 MDIO_WC_REG_RX66_CONTROL, (3<<13));
 
-       for (i = 0; i < sizeof(wc_regs)/sizeof(struct bnx2x_reg_set); i++)
+       for (i = 0; i < ARRAY_SIZE(wc_regs); i++)
                bnx2x_cl45_write(bp, phy, wc_regs[i].devad, wc_regs[i].reg,
                                 wc_regs[i].val);
 
@@ -9520,7 +9520,7 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
        } else {
                /* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
                /* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
-               for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set);
+               for (i = 0; i < ARRAY_SIZE(reg_set);
                      i++)
                        bnx2x_cl45_write(bp, phy, reg_set[i].devad,
                                         reg_set[i].reg, reg_set[i].val);
@@ -9592,7 +9592,7 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
                         MDIO_PMA_DEVAD,
                         MDIO_PMA_REG_8481_LINK_SIGNAL, val);
 
-       for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
 
@@ -13395,7 +13395,7 @@ static void bnx2x_disable_kr2(struct link_params *params,
        };
        DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
 
-       for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+       for (i = 0; i < ARRAY_SIZE(reg_set); i++)
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
        vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
index ee6e7ec854577b8687bb1e8688ed7e83261664cc..d25c7d79787a1bacdfb0dc526bc9814fdfab8d2d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2008-2012 Broadcom Corporation
+/* Copyright 2008-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
index 5523da3afcdccd23f4b90c6191f722d02063c1d3..c4daee1b72865180c33c96e906d55f8232f060bf 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_main.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -59,6 +59,7 @@
 #include "bnx2x_init.h"
 #include "bnx2x_init_ops.h"
 #include "bnx2x_cmn.h"
+#include "bnx2x_vfpf.h"
 #include "bnx2x_dcb.h"
 #include "bnx2x_sp.h"
 
@@ -144,39 +145,49 @@ enum bnx2x_board_type {
        BCM57711E,
        BCM57712,
        BCM57712_MF,
+       BCM57712_VF,
        BCM57800,
        BCM57800_MF,
+       BCM57800_VF,
        BCM57810,
        BCM57810_MF,
-       BCM57840_O,
+       BCM57810_VF,
        BCM57840_4_10,
        BCM57840_2_20,
-       BCM57840_MFO,
        BCM57840_MF,
+       BCM57840_VF,
        BCM57811,
-       BCM57811_MF
+       BCM57811_MF,
+       BCM57840_O,
+       BCM57840_MFO,
+       BCM57811_VF
 };
 
 /* indexed by board_type, above */
 static struct {
        char *name;
 } board_info[] = {
-       { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
-       { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
-       { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
-       { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
-       { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
-       { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
-       { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
-       { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
-       { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet"},
-       { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function"},
+       [BCM57710]      = { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
+       [BCM57711]      = { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
+       [BCM57711E]     = { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
+       [BCM57712]      = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
+       [BCM57712_MF]   = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
+       [BCM57712_VF]   = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" },
+       [BCM57800]      = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
+       [BCM57800_MF]   = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
+       [BCM57800_VF]   = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" },
+       [BCM57810]      = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
+       [BCM57810_MF]   = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
+       [BCM57810_VF]   = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" },
+       [BCM57840_4_10] = { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
+       [BCM57840_2_20] = { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
+       [BCM57840_MF]   = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+       [BCM57840_VF]   = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" },
+       [BCM57811]      = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" },
+       [BCM57811_MF]   = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" },
+       [BCM57840_O]    = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
+       [BCM57840_MFO]  = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+       [BCM57811_VF]   = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }
 };
 
 #ifndef PCI_DEVICE_ID_NX2_57710
@@ -194,12 +205,18 @@ static struct {
 #ifndef PCI_DEVICE_ID_NX2_57712_MF
 #define PCI_DEVICE_ID_NX2_57712_MF     CHIP_NUM_57712_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57712_VF
+#define PCI_DEVICE_ID_NX2_57712_VF     CHIP_NUM_57712_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57800
 #define PCI_DEVICE_ID_NX2_57800                CHIP_NUM_57800
 #endif
 #ifndef PCI_DEVICE_ID_NX2_57800_MF
 #define PCI_DEVICE_ID_NX2_57800_MF     CHIP_NUM_57800_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57800_VF
+#define PCI_DEVICE_ID_NX2_57800_VF     CHIP_NUM_57800_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57810
 #define PCI_DEVICE_ID_NX2_57810                CHIP_NUM_57810
 #endif
@@ -209,6 +226,9 @@ static struct {
 #ifndef PCI_DEVICE_ID_NX2_57840_O
 #define PCI_DEVICE_ID_NX2_57840_O      CHIP_NUM_57840_OBSOLETE
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57810_VF
+#define PCI_DEVICE_ID_NX2_57810_VF     CHIP_NUM_57810_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57840_4_10
 #define PCI_DEVICE_ID_NX2_57840_4_10   CHIP_NUM_57840_4_10
 #endif
@@ -221,29 +241,41 @@ static struct {
 #ifndef PCI_DEVICE_ID_NX2_57840_MF
 #define PCI_DEVICE_ID_NX2_57840_MF     CHIP_NUM_57840_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57840_VF
+#define PCI_DEVICE_ID_NX2_57840_VF     CHIP_NUM_57840_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57811
 #define PCI_DEVICE_ID_NX2_57811                CHIP_NUM_57811
 #endif
 #ifndef PCI_DEVICE_ID_NX2_57811_MF
 #define PCI_DEVICE_ID_NX2_57811_MF     CHIP_NUM_57811_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57811_VF
+#define PCI_DEVICE_ID_NX2_57811_VF     CHIP_NUM_57811_VF
+#endif
+
 static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712), BCM57712 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_MF), BCM57712_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_VF), BCM57712_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800), BCM57800 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_VF), BCM57800_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810), BCM57810 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_MF), BCM57810_MF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_O), BCM57840_O },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20), BCM57840_2_20 },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_VF), BCM57810_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MFO), BCM57840_MFO },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811), BCM57811 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_MF), BCM57811_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_VF), BCM57811_VF },
        { 0 }
 };
 
@@ -346,6 +378,65 @@ static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
 #define DMAE_DP_DST_PCI                "pci dst_addr [%x:%08x]"
 #define DMAE_DP_DST_NONE       "dst_addr [none]"
 
+void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl)
+{
+       u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;
+
+       switch (dmae->opcode & DMAE_COMMAND_DST) {
+       case DMAE_CMD_DST_PCI:
+               if (src_type == DMAE_CMD_SRC_PCI)
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%x:%08x], len [%d*4], dst [%x:%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+                          dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               else
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%08x], len [%d*4], dst [%x:%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_lo >> 2,
+                          dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               break;
+       case DMAE_CMD_DST_GRC:
+               if (src_type == DMAE_CMD_SRC_PCI)
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%x:%08x], len [%d*4], dst_addr [%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+                          dmae->len, dmae->dst_addr_lo >> 2,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               else
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%08x], len [%d*4], dst [%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_lo >> 2,
+                          dmae->len, dmae->dst_addr_lo >> 2,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               break;
+       default:
+               if (src_type == DMAE_CMD_SRC_PCI)
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src_addr [%x:%08x]  len [%d * 4]  dst_addr [none]\n"
+                          "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+                          dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               else
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src_addr [%08x]  len [%d * 4]  dst_addr [none]\n"
+                          "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_lo >> 2,
+                          dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               break;
+       }
+}
 
 /* copy command into DMAE command memory and set DMAE command go */
 void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
@@ -396,7 +487,7 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
        return opcode;
 }
 
-static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
+void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
                                      struct dmae_command *dmae,
                                      u8 src_type, u8 dst_type)
 {
@@ -412,9 +503,8 @@ static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
        dmae->comp_val = DMAE_COMP_VAL;
 }
 
-/* issue a dmae command over the init-channel and wailt for completion */
-static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp,
-                                     struct dmae_command *dmae)
+/* issue a dmae command over the init-channel and wait for completion */
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
 {
        u32 *wb_comp = bnx2x_sp(bp, wb_comp);
        int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
@@ -692,12 +782,16 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
        printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);
 
        printk("%s", lvl);
+
+       /* dump buffer after the mark */
        for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
                        data[word] = htonl(REG_RD(bp, offset + 4*word));
                data[8] = 0x0;
                pr_cont("%s", (char *)data);
        }
+
+       /* dump buffer before the mark */
        for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
                        data[word] = htonl(REG_RD(bp, offset + 4*word));
@@ -712,7 +806,71 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
        bnx2x_fw_dump_lvl(bp, KERN_ERR);
 }
 
-void bnx2x_panic_dump(struct bnx2x *bp)
+static void bnx2x_hc_int_disable(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+       u32 val = REG_RD(bp, addr);
+
+       /* in E1 we must use only PCI configuration space to disable
+        * MSI/MSIX capablility
+        * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
+        */
+       if (CHIP_IS_E1(bp)) {
+               /* Since IGU_PF_CONF_MSI_MSIX_EN still always on
+                * Use mask register to prevent from HC sending interrupts
+                * after we exit the function
+                */
+               REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
+
+               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
+                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+       } else
+               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+                        HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
+                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+       DP(NETIF_MSG_IFDOWN,
+          "write %x to HC %d (addr 0x%x)\n",
+          val, port, addr);
+
+       /* flush all outstanding writes */
+       mmiowb();
+
+       REG_WR(bp, addr, val);
+       if (REG_RD(bp, addr) != val)
+               BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_igu_int_disable(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
+
+       val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
+                IGU_PF_CONF_INT_LINE_EN |
+                IGU_PF_CONF_ATTN_BIT_EN);
+
+       DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
+
+       /* flush all outstanding writes */
+       mmiowb();
+
+       REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+       if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
+               BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_int_disable(struct bnx2x *bp)
+{
+       if (bp->common.int_block == INT_BLOCK_HC)
+               bnx2x_hc_int_disable(bp);
+       else
+               bnx2x_igu_int_disable(bp);
+}
+
+void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
 {
        int i;
        u16 j;
@@ -722,6 +880,8 @@ void bnx2x_panic_dump(struct bnx2x *bp)
        u16 start = 0, end = 0;
        u8 cos;
 #endif
+       if (disable_int)
+               bnx2x_int_disable(bp);
 
        bp->stats_state = STATS_STATE_DISABLED;
        bp->eth_stats.unrecoverable_error++;
@@ -867,6 +1027,17 @@ void bnx2x_panic_dump(struct bnx2x *bp)
        }
 
 #ifdef BNX2X_STOP_ON_ERROR
+
+       /* event queue */
+       for (i = 0; i < NUM_EQ_DESC; i++) {
+               u32 *data = (u32 *)&bp->eq_ring[i].message.data;
+
+               BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
+                         i, bp->eq_ring[i].message.opcode,
+                         bp->eq_ring[i].message.error);
+               BNX2X_ERR("data: %x %x %x\n", data[0], data[1], data[2]);
+       }
+
        /* Rings */
        /* Rx */
        for_each_valid_rx_queue(bp, i) {
@@ -1038,8 +1209,8 @@ static u32 bnx2x_flr_clnup_reg_poll(struct bnx2x *bp, u32 reg,
        return val;
 }
 
-static int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
-                                          char *msg, u32 poll_cnt)
+int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
+                                   char *msg, u32 poll_cnt)
 {
        u32 val = bnx2x_flr_clnup_reg_poll(bp, reg, 0, poll_cnt);
        if (val != 0) {
@@ -1049,7 +1220,8 @@ static int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
        return 0;
 }
 
-static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
+/* Common routines with VF FLR cleanup */
+u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
 {
        /* adjust polling timeout */
        if (CHIP_REV_IS_EMUL(bp))
@@ -1061,7 +1233,7 @@ static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
        return FLR_POLL_CNT;
 }
 
-static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
+void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
 {
        struct pbf_pN_cmd_regs cmd_regs[] = {
                {0, (CHIP_IS_E3B0(bp)) ?
@@ -1136,10 +1308,9 @@ static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
        (((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)
 
 
-static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
-                                        u32 poll_cnt)
+int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
 {
-       struct sdm_op_gen op_gen = {0};
+       u32 op_gen_command = 0;
 
        u32 comp_addr = BAR_CSTRORM_INTMEM +
                        CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func);
@@ -1150,19 +1321,20 @@ static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
                return 1;
        }
 
-       op_gen.command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
-       op_gen.command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
-       op_gen.command |= OP_GEN_AGG_VECT(clnup_func);
-       op_gen.command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
+       op_gen_command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
+       op_gen_command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
+       op_gen_command |= OP_GEN_AGG_VECT(clnup_func);
+       op_gen_command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
 
        DP(BNX2X_MSG_SP, "sending FW Final cleanup\n");
-       REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen.command);
+       REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen_command);
 
        if (bnx2x_flr_clnup_reg_poll(bp, comp_addr, 1, poll_cnt) != 1) {
                BNX2X_ERR("FW final cleanup did not succeed\n");
                DP(BNX2X_MSG_SP, "At timeout completion address contained %x\n",
                   (REG_RD(bp, comp_addr)));
-               ret = 1;
+               bnx2x_panic();
+               return 1;
        }
        /* Zero completion for nxt FLR */
        REG_WR(bp, comp_addr, 0);
@@ -1170,7 +1342,7 @@ static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
        return ret;
 }
 
-static u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
+u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
 {
        u16 status;
 
@@ -1382,26 +1554,31 @@ static void bnx2x_igu_int_enable(struct bnx2x *bp)
        if (msix) {
                val &= ~(IGU_PF_CONF_INT_LINE_EN |
                         IGU_PF_CONF_SINGLE_ISR_EN);
-               val |= (IGU_PF_CONF_FUNC_EN |
-                       IGU_PF_CONF_MSI_MSIX_EN |
+               val |= (IGU_PF_CONF_MSI_MSIX_EN |
                        IGU_PF_CONF_ATTN_BIT_EN);
 
                if (single_msix)
                        val |= IGU_PF_CONF_SINGLE_ISR_EN;
        } else if (msi) {
                val &= ~IGU_PF_CONF_INT_LINE_EN;
-               val |= (IGU_PF_CONF_FUNC_EN |
-                       IGU_PF_CONF_MSI_MSIX_EN |
+               val |= (IGU_PF_CONF_MSI_MSIX_EN |
                        IGU_PF_CONF_ATTN_BIT_EN |
                        IGU_PF_CONF_SINGLE_ISR_EN);
        } else {
                val &= ~IGU_PF_CONF_MSI_MSIX_EN;
-               val |= (IGU_PF_CONF_FUNC_EN |
-                       IGU_PF_CONF_INT_LINE_EN |
+               val |= (IGU_PF_CONF_INT_LINE_EN |
                        IGU_PF_CONF_ATTN_BIT_EN |
                        IGU_PF_CONF_SINGLE_ISR_EN);
        }
 
+       /* Clean previous status - need to configure igu prior to ack*/
+       if ((!msix) || single_msix) {
+               REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+               bnx2x_ack_int(bp);
+       }
+
+       val |= IGU_PF_CONF_FUNC_EN;
+
        DP(NETIF_MSG_IFUP, "write 0x%x to IGU  mode %s\n",
           val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 
@@ -1436,71 +1613,6 @@ void bnx2x_int_enable(struct bnx2x *bp)
                bnx2x_igu_int_enable(bp);
 }
 
-static void bnx2x_hc_int_disable(struct bnx2x *bp)
-{
-       int port = BP_PORT(bp);
-       u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
-       u32 val = REG_RD(bp, addr);
-
-       /*
-        * in E1 we must use only PCI configuration space to disable
-        * MSI/MSIX capablility
-        * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
-        */
-       if (CHIP_IS_E1(bp)) {
-               /*  Since IGU_PF_CONF_MSI_MSIX_EN still always on
-                *  Use mask register to prevent from HC sending interrupts
-                *  after we exit the function
-                */
-               REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
-
-               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
-                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-       } else
-               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-                        HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
-                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
-                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-
-       DP(NETIF_MSG_IFDOWN,
-          "write %x to HC %d (addr 0x%x)\n",
-          val, port, addr);
-
-       /* flush all outstanding writes */
-       mmiowb();
-
-       REG_WR(bp, addr, val);
-       if (REG_RD(bp, addr) != val)
-               BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_igu_int_disable(struct bnx2x *bp)
-{
-       u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
-
-       val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
-                IGU_PF_CONF_INT_LINE_EN |
-                IGU_PF_CONF_ATTN_BIT_EN);
-
-       DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
-
-       /* flush all outstanding writes */
-       mmiowb();
-
-       REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
-       if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
-               BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_int_disable(struct bnx2x *bp)
-{
-       if (bp->common.int_block == INT_BLOCK_HC)
-               bnx2x_hc_int_disable(bp);
-       else
-               bnx2x_igu_int_disable(bp);
-}
-
 void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
 {
        int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
@@ -1586,11 +1698,11 @@ static int bnx2x_get_leader_lock_resource(struct bnx2x *bp)
 }
 
 /**
- * bnx2x_trylock_leader_lock- try to aquire a leader lock.
+ * bnx2x_trylock_leader_lock- try to acquire a leader lock.
  *
  * @bp: driver handle
  *
- * Tries to aquire a leader lock for current engine.
+ * Tries to acquire a leader lock for current engine.
  */
 static bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
 {
@@ -1599,6 +1711,24 @@ static bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
 
 static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err);
 
+/* schedule the sp task and mark that interrupt occurred (runs from ISR) */
+static int bnx2x_schedule_sp_task(struct bnx2x *bp)
+{
+       /* Set the interrupt occurred bit for the sp-task to recognize it
+        * must ack the interrupt and transition according to the IGU
+        * state machine.
+        */
+       atomic_set(&bp->interrupt_occurred, 1);
+
+       /* The sp_task must execute only after this bit
+        * is set, otherwise we will get out of sync and miss all
+        * further interrupts. Hence, the barrier.
+        */
+       smp_wmb();
+
+       /* schedule sp_task to workqueue */
+       return queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+}
 
 void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 {
@@ -1613,6 +1743,13 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
           fp->index, cid, command, bp->state,
           rr_cqe->ramrod_cqe.ramrod_type);
 
+       /* If cid is within VF range, replace the slowpath object with the
+        * one corresponding to this VF
+        */
+       if (cid >= BNX2X_FIRST_VF_CID  &&
+           cid < BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)
+               bnx2x_iov_set_queue_sp_obj(bp, cid, &q_obj);
+
        switch (command) {
        case (RAMROD_CMD_ID_ETH_CLIENT_UPDATE):
                DP(BNX2X_MSG_SP, "got UPDATE ramrod. CID %d\n", cid);
@@ -1664,6 +1801,8 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 #else
                return;
 #endif
+       /* SRIOV: reschedule any 'in_progress' operations */
+       bnx2x_iov_sp_event(bp, cid, true);
 
        smp_mb__before_atomic_inc();
        atomic_inc(&bp->cq_spq_left);
@@ -1680,7 +1819,7 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
                 * mark pending ACK to MCP bit.
                 * prevent case that both bits are cleared.
                 * At the end of load/unload driver checks that
-                * sp_state is cleaerd, and this order prevents
+                * sp_state is cleared, and this order prevents
                 * races
                 */
                smp_mb__before_clear_bit();
@@ -1689,22 +1828,13 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
                clear_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state);
                smp_mb__after_clear_bit();
 
-               /* schedule workqueue to send ack to MCP */
-               queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+               /* schedule the sp task as mcp ack is required */
+               bnx2x_schedule_sp_task(bp);
        }
 
        return;
 }
 
-void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-                       u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod)
-{
-       u32 start = BAR_USTRORM_INTMEM + fp->ustorm_rx_prods_offset;
-
-       bnx2x_update_rx_prod_gen(bp, fp, bd_prod, rx_comp_prod, rx_sge_prod,
-                                start);
-}
-
 irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
 {
        struct bnx2x *bp = netdev_priv(dev_instance);
@@ -1745,21 +1875,23 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
                if (status & (mask | 0x1)) {
                        struct cnic_ops *c_ops = NULL;
 
-                       if (likely(bp->state == BNX2X_STATE_OPEN)) {
-                               rcu_read_lock();
-                               c_ops = rcu_dereference(bp->cnic_ops);
-                               if (c_ops)
-                                       c_ops->cnic_handler(bp->cnic_data,
-                                                           NULL);
-                               rcu_read_unlock();
-                       }
+                       rcu_read_lock();
+                       c_ops = rcu_dereference(bp->cnic_ops);
+                       if (c_ops && (bp->cnic_eth_dev.drv_state &
+                                     CNIC_DRV_STATE_HANDLES_IRQ))
+                               c_ops->cnic_handler(bp->cnic_data, NULL);
+                       rcu_read_unlock();
 
                        status &= ~mask;
                }
        }
 
        if (unlikely(status & 0x1)) {
-               queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+
+               /* schedule sp task to perform default status block work, ack
+                * attentions and enable interrupts.
+                */
+               bnx2x_schedule_sp_task(bp);
 
                status &= ~0x1;
                if (!status)
@@ -2459,23 +2591,55 @@ void bnx2x__link_status_update(struct bnx2x *bp)
                return;
 
        /* read updated dcb configuration */
-       bnx2x_dcbx_pmf_update(bp);
-
-       bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+       if (IS_PF(bp)) {
+               bnx2x_dcbx_pmf_update(bp);
+               bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+               if (bp->link_vars.link_up)
+                       bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
+               else
+                       bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+                       /* indicate link status */
+               bnx2x_link_report(bp);
 
-       if (bp->link_vars.link_up)
+       } else { /* VF */
+               bp->port.supported[0] |= (SUPPORTED_10baseT_Half |
+                                         SUPPORTED_10baseT_Full |
+                                         SUPPORTED_100baseT_Half |
+                                         SUPPORTED_100baseT_Full |
+                                         SUPPORTED_1000baseT_Full |
+                                         SUPPORTED_2500baseX_Full |
+                                         SUPPORTED_10000baseT_Full |
+                                         SUPPORTED_TP |
+                                         SUPPORTED_FIBRE |
+                                         SUPPORTED_Autoneg |
+                                         SUPPORTED_Pause |
+                                         SUPPORTED_Asym_Pause);
+               bp->port.advertising[0] = bp->port.supported[0];
+
+               bp->link_params.bp = bp;
+               bp->link_params.port = BP_PORT(bp);
+               bp->link_params.req_duplex[0] = DUPLEX_FULL;
+               bp->link_params.req_flow_ctrl[0] = BNX2X_FLOW_CTRL_NONE;
+               bp->link_params.req_line_speed[0] = SPEED_10000;
+               bp->link_params.speed_cap_mask[0] = 0x7f0000;
+               bp->link_params.switch_cfg = SWITCH_CFG_10G;
+               bp->link_vars.mac_type = MAC_TYPE_BMAC;
+               bp->link_vars.line_speed = SPEED_10000;
+               bp->link_vars.link_status =
+                       (LINK_STATUS_LINK_UP |
+                        LINK_STATUS_SPEED_AND_DUPLEX_10GTFD);
+               bp->link_vars.link_up = 1;
+               bp->link_vars.duplex = DUPLEX_FULL;
+               bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+               __bnx2x_link_report(bp);
                bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
-       else
-               bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-       /* indicate link status */
-       bnx2x_link_report(bp);
+       }
 }
 
 static int bnx2x_afex_func_update(struct bnx2x *bp, u16 vifid,
                                  u16 vlan_val, u8 allowed_prio)
 {
-       struct bnx2x_func_state_params func_params = {0};
+       struct bnx2x_func_state_params func_params = {NULL};
        struct bnx2x_func_afex_update_params *f_update_params =
                &func_params.params.afex_update;
 
@@ -2500,7 +2664,7 @@ static int bnx2x_afex_func_update(struct bnx2x *bp, u16 vifid,
 static int bnx2x_afex_handle_vif_list_cmd(struct bnx2x *bp, u8 cmd_type,
                                          u16 vif_index, u8 func_bit_map)
 {
-       struct bnx2x_func_state_params func_params = {0};
+       struct bnx2x_func_state_params func_params = {NULL};
        struct bnx2x_func_afex_viflists_params *update_params =
                &func_params.params.afex_viflists;
        int rc;
@@ -2516,7 +2680,7 @@ static int bnx2x_afex_handle_vif_list_cmd(struct bnx2x *bp, u8 cmd_type,
 
        /* set parameters according to cmd_type */
        update_params->afex_vif_list_command = cmd_type;
-       update_params->vif_list_index = cpu_to_le16(vif_index);
+       update_params->vif_list_index = vif_index;
        update_params->func_bit_map =
                (cmd_type == VIF_LIST_RULE_GET) ? 0 : func_bit_map;
        update_params->func_to_clear = 0;
@@ -2800,6 +2964,10 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp,
                __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
 
 
+#ifdef BNX2X_STOP_ON_ERROR
+       __set_bit(BNX2X_Q_FLG_TX_SEC, &flags);
+#endif
+
        return flags;
 }
 
@@ -2875,15 +3043,12 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
                                pause->sge_th_hi + FW_PREFETCH_CNT >
                                MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES);
 
-               tpa_agg_size = min_t(u32,
-                       (min_t(u32, 8, MAX_SKB_FRAGS) *
-                       SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
+               tpa_agg_size = TPA_AGG_SIZE;
                max_sge = SGE_PAGE_ALIGN(bp->dev->mtu) >>
                        SGE_PAGE_SHIFT;
                max_sge = ((max_sge + PAGES_PER_SGE - 1) &
                          (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
-               sge_sz = (u16)min_t(u32, SGE_PAGE_SIZE * PAGES_PER_SGE,
-                                   0xffff);
+               sge_sz = (u16)min_t(u32, SGE_PAGES, 0xffff);
        }
 
        /* pause - not for e1 */
@@ -2928,7 +3093,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
 
        /* Maximum number or simultaneous TPA aggregation for this Queue.
         *
-        * For PF Clients it should be the maximum avaliable number.
+        * For PF Clients it should be the maximum available number.
         * VF driver(s) may want to define it to a smaller value.
         */
        rxq_init->max_tpa_queues = MAX_AGG_QS(bp);
@@ -3022,7 +3187,7 @@ static void bnx2x_pf_init(struct bnx2x *bp)
        if (bp->port.pmf)
                storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
 
-       /* init Event Queue */
+       /* init Event Queue - PCI bus guarantees correct endianity*/
        eq_data.base_addr.hi = U64_HI(bp->eq_mapping);
        eq_data.base_addr.lo = U64_LO(bp->eq_mapping);
        eq_data.producer = bp->eq_prod;
@@ -3112,65 +3277,75 @@ static void bnx2x_drv_info_fcoe_stat(struct bnx2x *bp)
                struct fcoe_statistics_params *fw_fcoe_stat =
                        &bp->fw_stats_data->fcoe;
 
-               ADD_64(fcoe_stat->rx_bytes_hi, 0, fcoe_stat->rx_bytes_lo,
-                      fw_fcoe_stat->rx_stat0.fcoe_rx_byte_cnt);
+               ADD_64_LE(fcoe_stat->rx_bytes_hi, LE32_0,
+                         fcoe_stat->rx_bytes_lo,
+                         fw_fcoe_stat->rx_stat0.fcoe_rx_byte_cnt);
 
-               ADD_64(fcoe_stat->rx_bytes_hi,
-                      fcoe_q_tstorm_stats->rcv_ucast_bytes.hi,
-                      fcoe_stat->rx_bytes_lo,
-                      fcoe_q_tstorm_stats->rcv_ucast_bytes.lo);
+               ADD_64_LE(fcoe_stat->rx_bytes_hi,
+                         fcoe_q_tstorm_stats->rcv_ucast_bytes.hi,
+                         fcoe_stat->rx_bytes_lo,
+                         fcoe_q_tstorm_stats->rcv_ucast_bytes.lo);
 
-               ADD_64(fcoe_stat->rx_bytes_hi,
-                      fcoe_q_tstorm_stats->rcv_bcast_bytes.hi,
-                      fcoe_stat->rx_bytes_lo,
-                      fcoe_q_tstorm_stats->rcv_bcast_bytes.lo);
+               ADD_64_LE(fcoe_stat->rx_bytes_hi,
+                         fcoe_q_tstorm_stats->rcv_bcast_bytes.hi,
+                         fcoe_stat->rx_bytes_lo,
+                         fcoe_q_tstorm_stats->rcv_bcast_bytes.lo);
 
-               ADD_64(fcoe_stat->rx_bytes_hi,
-                      fcoe_q_tstorm_stats->rcv_mcast_bytes.hi,
-                      fcoe_stat->rx_bytes_lo,
-                      fcoe_q_tstorm_stats->rcv_mcast_bytes.lo);
+               ADD_64_LE(fcoe_stat->rx_bytes_hi,
+                         fcoe_q_tstorm_stats->rcv_mcast_bytes.hi,
+                         fcoe_stat->rx_bytes_lo,
+                         fcoe_q_tstorm_stats->rcv_mcast_bytes.lo);
 
-               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-                      fw_fcoe_stat->rx_stat0.fcoe_rx_pkt_cnt);
+               ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+                         fcoe_stat->rx_frames_lo,
+                         fw_fcoe_stat->rx_stat0.fcoe_rx_pkt_cnt);
 
-               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-                      fcoe_q_tstorm_stats->rcv_ucast_pkts);
+               ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+                         fcoe_stat->rx_frames_lo,
+                         fcoe_q_tstorm_stats->rcv_ucast_pkts);
 
-               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-                      fcoe_q_tstorm_stats->rcv_bcast_pkts);
+               ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+                         fcoe_stat->rx_frames_lo,
+                         fcoe_q_tstorm_stats->rcv_bcast_pkts);
 
-               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-                      fcoe_q_tstorm_stats->rcv_mcast_pkts);
+               ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+                         fcoe_stat->rx_frames_lo,
+                         fcoe_q_tstorm_stats->rcv_mcast_pkts);
 
-               ADD_64(fcoe_stat->tx_bytes_hi, 0, fcoe_stat->tx_bytes_lo,
-                      fw_fcoe_stat->tx_stat.fcoe_tx_byte_cnt);
+               ADD_64_LE(fcoe_stat->tx_bytes_hi, LE32_0,
+                         fcoe_stat->tx_bytes_lo,
+                         fw_fcoe_stat->tx_stat.fcoe_tx_byte_cnt);
 
-               ADD_64(fcoe_stat->tx_bytes_hi,
-                      fcoe_q_xstorm_stats->ucast_bytes_sent.hi,
-                      fcoe_stat->tx_bytes_lo,
-                      fcoe_q_xstorm_stats->ucast_bytes_sent.lo);
+               ADD_64_LE(fcoe_stat->tx_bytes_hi,
+                         fcoe_q_xstorm_stats->ucast_bytes_sent.hi,
+                         fcoe_stat->tx_bytes_lo,
+                         fcoe_q_xstorm_stats->ucast_bytes_sent.lo);
 
-               ADD_64(fcoe_stat->tx_bytes_hi,
-                      fcoe_q_xstorm_stats->bcast_bytes_sent.hi,
-                      fcoe_stat->tx_bytes_lo,
-                      fcoe_q_xstorm_stats->bcast_bytes_sent.lo);
+               ADD_64_LE(fcoe_stat->tx_bytes_hi,
+                         fcoe_q_xstorm_stats->bcast_bytes_sent.hi,
+                         fcoe_stat->tx_bytes_lo,
+                         fcoe_q_xstorm_stats->bcast_bytes_sent.lo);
 
-               ADD_64(fcoe_stat->tx_bytes_hi,
-                      fcoe_q_xstorm_stats->mcast_bytes_sent.hi,
-                      fcoe_stat->tx_bytes_lo,
-                      fcoe_q_xstorm_stats->mcast_bytes_sent.lo);
+               ADD_64_LE(fcoe_stat->tx_bytes_hi,
+                         fcoe_q_xstorm_stats->mcast_bytes_sent.hi,
+                         fcoe_stat->tx_bytes_lo,
+                         fcoe_q_xstorm_stats->mcast_bytes_sent.lo);
 
-               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-                      fw_fcoe_stat->tx_stat.fcoe_tx_pkt_cnt);
+               ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+                         fcoe_stat->tx_frames_lo,
+                         fw_fcoe_stat->tx_stat.fcoe_tx_pkt_cnt);
 
-               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-                      fcoe_q_xstorm_stats->ucast_pkts_sent);
+               ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+                         fcoe_stat->tx_frames_lo,
+                         fcoe_q_xstorm_stats->ucast_pkts_sent);
 
-               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-                      fcoe_q_xstorm_stats->bcast_pkts_sent);
+               ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+                         fcoe_stat->tx_frames_lo,
+                         fcoe_q_xstorm_stats->bcast_pkts_sent);
 
-               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-                      fcoe_q_xstorm_stats->mcast_pkts_sent);
+               ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+                         fcoe_stat->tx_frames_lo,
+                         fcoe_q_xstorm_stats->mcast_pkts_sent);
        }
 
        /* ask L5 driver to add data to the struct */
@@ -3641,7 +3816,7 @@ static void bnx2x_fan_failure(struct bnx2x *bp)
                            "Please contact OEM Support for assistance\n");
 
        /*
-        * Scheudle device reset (unload)
+        * Schedule device reset (unload)
         * This is due to some boards consuming sufficient power when driver is
         * up to overheat if fan fails.
         */
@@ -3791,6 +3966,10 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
 
                        if (val & DRV_STATUS_DRV_INFO_REQ)
                                bnx2x_handle_drv_info_req(bp);
+
+                       if (val & DRV_STATUS_VF_DISABLED)
+                               bnx2x_vf_handle_flr_event(bp);
+
                        if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
                                bnx2x_pmf_update(bp);
 
@@ -4587,8 +4766,8 @@ static void bnx2x_attn_int(struct bnx2x *bp)
 void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment,
                      u16 index, u8 op, u8 update)
 {
-       u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
-
+       u32 igu_addr = bp->igu_base_addr;
+       igu_addr += (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
        bnx2x_igu_ack_sb_gen(bp, igu_sb_id, segment, index, op, update,
                             igu_addr);
 }
@@ -4616,7 +4795,7 @@ static int  bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid,
 
                BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n",
                          cid);
-               bnx2x_panic_dump(bp);
+               bnx2x_panic_dump(bp, false);
        }
        bnx2x_cnic_cfc_comp(bp, cid, err);
        return 0;
@@ -4658,7 +4837,8 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
        /* Always push next commands out, don't wait here */
        __set_bit(RAMROD_CONT, &ramrod_flags);
 
-       switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+       switch (le32_to_cpu((__force __le32)elem->message.data.eth_event.echo)
+                           >> BNX2X_SWCID_SHIFT) {
        case BNX2X_FILTER_MAC_PENDING:
                DP(BNX2X_MSG_SP, "Got SETUP_MAC completions\n");
                if (CNIC_LOADED(bp) && (cid == BNX2X_ISCSI_ETH_CID(bp)))
@@ -4735,7 +4915,7 @@ static void bnx2x_after_function_update(struct bnx2x *bp)
        struct bnx2x_queue_update_params *q_update_params =
                &queue_params.params.update;
 
-       /* Send Q update command with afex vlan removal values  for all Qs */
+       /* Send Q update command with afex vlan removal values for all Qs */
        queue_params.cmd = BNX2X_Q_CMD_UPDATE;
 
        /* set silent vlan removal values according to vlan mode */
@@ -4809,7 +4989,7 @@ static void bnx2x_eq_int(struct bnx2x *bp)
        u8 echo;
        u32 cid;
        u8 opcode;
-       int spqe_cnt = 0;
+       int rc, spqe_cnt = 0;
        struct bnx2x_queue_sp_obj *q_obj;
        struct bnx2x_func_sp_obj *f_obj = &bp->func_obj;
        struct bnx2x_raw_obj *rss_raw = &bp->rss_conf_obj.raw;
@@ -4837,15 +5017,27 @@ static void bnx2x_eq_int(struct bnx2x *bp)
        for (; sw_cons != hw_cons;
              sw_prod = NEXT_EQ_IDX(sw_prod), sw_cons = NEXT_EQ_IDX(sw_cons)) {
 
-
                elem = &bp->eq_ring[EQ_DESC(sw_cons)];
 
-               cid = SW_CID(elem->message.data.cfc_del_event.cid);
-               opcode = elem->message.opcode;
+               rc = bnx2x_iov_eq_sp_event(bp, elem);
+               if (!rc) {
+                       DP(BNX2X_MSG_IOV, "bnx2x_iov_eq_sp_event returned %d\n",
+                          rc);
+                       goto next_spqe;
+               }
 
+               /* elem CID originates from FW; actually LE */
+               cid = SW_CID((__force __le32)
+                            elem->message.data.cfc_del_event.cid);
+               opcode = elem->message.opcode;
 
                /* handle eq element */
                switch (opcode) {
+               case EVENT_RING_OPCODE_VF_PF_CHANNEL:
+                       DP(BNX2X_MSG_IOV, "vf pf channel element on eq\n");
+                       bnx2x_vf_mbx(bp, &elem->message.data.vf_pf_event);
+                       continue;
+
                case EVENT_RING_OPCODE_STAT_QUERY:
                        DP(BNX2X_MSG_SP | BNX2X_MSG_STATS,
                           "got statistics comp event %d\n",
@@ -5011,50 +5203,65 @@ next_spqe:
 static void bnx2x_sp_task(struct work_struct *work)
 {
        struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
-       u16 status;
 
-       status = bnx2x_update_dsb_idx(bp);
-/*     if (status == 0)                                     */
-/*             BNX2X_ERR("spurious slowpath interrupt!\n"); */
+       DP(BNX2X_MSG_SP, "sp task invoked\n");
 
-       DP(BNX2X_MSG_SP, "got a slowpath interrupt (status 0x%x)\n", status);
+       /* make sure the atomic interupt_occurred has been written */
+       smp_rmb();
+       if (atomic_read(&bp->interrupt_occurred)) {
 
-       /* HW attentions */
-       if (status & BNX2X_DEF_SB_ATT_IDX) {
-               bnx2x_attn_int(bp);
-               status &= ~BNX2X_DEF_SB_ATT_IDX;
-       }
+               /* what work needs to be performed? */
+               u16 status = bnx2x_update_dsb_idx(bp);
+
+               DP(BNX2X_MSG_SP, "status %x\n", status);
+               DP(BNX2X_MSG_SP, "setting interrupt_occurred to 0\n");
+               atomic_set(&bp->interrupt_occurred, 0);
 
-       /* SP events: STAT_QUERY and others */
-       if (status & BNX2X_DEF_SB_IDX) {
-               struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
+               /* HW attentions */
+               if (status & BNX2X_DEF_SB_ATT_IDX) {
+                       bnx2x_attn_int(bp);
+                       status &= ~BNX2X_DEF_SB_ATT_IDX;
+               }
+
+               /* SP events: STAT_QUERY and others */
+               if (status & BNX2X_DEF_SB_IDX) {
+                       struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
 
                if (FCOE_INIT(bp) &&
-                   (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
-                       /*
-                        * Prevent local bottom-halves from running as
-                        * we are going to change the local NAPI list.
-                        */
-                       local_bh_disable();
-                       napi_schedule(&bnx2x_fcoe(bp, napi));
-                       local_bh_enable();
+                           (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+                               /* Prevent local bottom-halves from running as
+                                * we are going to change the local NAPI list.
+                                */
+                               local_bh_disable();
+                               napi_schedule(&bnx2x_fcoe(bp, napi));
+                               local_bh_enable();
+                       }
+
+                       /* Handle EQ completions */
+                       bnx2x_eq_int(bp);
+                       bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
+                                    le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+
+                       status &= ~BNX2X_DEF_SB_IDX;
                }
 
-               /* Handle EQ completions */
-               bnx2x_eq_int(bp);
+               /* if status is non zero then perhaps something went wrong */
+               if (unlikely(status))
+                       DP(BNX2X_MSG_SP,
+                          "got an unknown interrupt! (status 0x%x)\n", status);
 
-               bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
-                       le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+               /* ack status block only if something was actually handled */
+               bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
+                            le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
 
-               status &= ~BNX2X_DEF_SB_IDX;
        }
 
-       if (unlikely(status))
-               DP(BNX2X_MSG_SP, "got an unknown interrupt! (status 0x%x)\n",
-                  status);
-
-       bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
-            le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
+       /* must be called after the EQ processing (since eq leads to sriov
+        * ramrod completion flows).
+        * This flow may have been scheduled by the arrival of a ramrod
+        * completion, or by the sriov code rescheduling itself.
+        */
+       bnx2x_iov_sp_task(bp);
 
        /* afex - poll to check if VIFSET_ACK should be sent to MFW */
        if (test_and_clear_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK,
@@ -5087,7 +5294,10 @@ irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
                rcu_read_unlock();
        }
 
-       queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+       /* schedule sp task to perform default status block work, ack
+        * attentions and enable interrupts.
+        */
+       bnx2x_schedule_sp_task(bp);
 
        return IRQ_HANDLED;
 }
@@ -5101,7 +5311,6 @@ void bnx2x_drv_pulse(struct bnx2x *bp)
                 bp->fw_drv_pulse_wr_seq);
 }
 
-
 static void bnx2x_timer(unsigned long data)
 {
        struct bnx2x *bp = (struct bnx2x *) data;
@@ -5109,7 +5318,8 @@ static void bnx2x_timer(unsigned long data)
        if (!netif_running(bp->dev))
                return;
 
-       if (!BP_NOMCP(bp)) {
+       if (IS_PF(bp) &&
+           !BP_NOMCP(bp)) {
                int mb_idx = BP_FW_MB_IDX(bp);
                u32 drv_pulse;
                u32 mcp_pulse;
@@ -5136,6 +5346,10 @@ static void bnx2x_timer(unsigned long data)
        if (bp->state == BNX2X_STATE_OPEN)
                bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
 
+       /* sample pf vf bulletin board for new posts from pf */
+       if (IS_VF(bp))
+               bnx2x_sample_bulletin(bp);
+
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 }
 
@@ -5278,7 +5492,7 @@ static void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
                SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
 }
 
-static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
+void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
                          u8 vf_valid, int fw_sb_id, int igu_sb_id)
 {
        int igu_seg_id;
@@ -5334,7 +5548,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
 
        DP(NETIF_MSG_IFUP, "Init FW SB %d\n", fw_sb_id);
 
-       /* write indecies to HW */
+       /* write indices to HW - PCI guarantees endianity of regpairs */
        bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size);
 }
 
@@ -5422,6 +5636,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
 
        bnx2x_zero_sp_sb(bp);
 
+       /* PCI guarantees endianity of regpairs */
        sp_sb_data.state                = SB_ENABLED;
        sp_sb_data.host_sb_addr.lo      = U64_LO(section);
        sp_sb_data.host_sb_addr.hi      = U64_HI(section);
@@ -5478,13 +5693,12 @@ static void bnx2x_init_eq_ring(struct bnx2x *bp)
                min_t(int, MAX_SP_DESC_CNT - MAX_SPQ_PENDING, NUM_EQ_DESC) - 1);
 }
 
-
 /* called with netif_addr_lock_bh() */
-void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
-                        unsigned long rx_mode_flags,
-                        unsigned long rx_accept_flags,
-                        unsigned long tx_accept_flags,
-                        unsigned long ramrod_flags)
+int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+                       unsigned long rx_mode_flags,
+                       unsigned long rx_accept_flags,
+                       unsigned long tx_accept_flags,
+                       unsigned long ramrod_flags)
 {
        struct bnx2x_rx_mode_ramrod_params ramrod_param;
        int rc;
@@ -5514,22 +5728,21 @@ void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
        rc = bnx2x_config_rx_mode(bp, &ramrod_param);
        if (rc < 0) {
                BNX2X_ERR("Set rx_mode %d failed\n", bp->rx_mode);
-               return;
+               return rc;
        }
+
+       return 0;
 }
 
-/* called with netif_addr_lock_bh() */
-void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
+                                  unsigned long *rx_accept_flags,
+                                  unsigned long *tx_accept_flags)
 {
-       unsigned long rx_mode_flags = 0, ramrod_flags = 0;
-       unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
-
-       if (!NO_FCOE(bp))
-
-               /* Configure rx_mode of FCoE Queue */
-               __set_bit(BNX2X_RX_MODE_FCOE_ETH, &rx_mode_flags);
+       /* Clear the flags first */
+       *rx_accept_flags = 0;
+       *tx_accept_flags = 0;
 
-       switch (bp->rx_mode) {
+       switch (rx_mode) {
        case BNX2X_RX_MODE_NONE:
                /*
                 * 'drop all' supersedes any accept flags that may have been
@@ -5537,25 +5750,25 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
                 */
                break;
        case BNX2X_RX_MODE_NORMAL:
-               __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_MULTICAST, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_MULTICAST, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
 
                /* internal switching mode */
-               __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_MULTICAST, &tx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_MULTICAST, tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
 
                break;
        case BNX2X_RX_MODE_ALLMULTI:
-               __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
 
                /* internal switching mode */
-               __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
 
                break;
        case BNX2X_RX_MODE_PROMISC:
@@ -5563,36 +5776,57 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
                 * should receive matched and unmatched (in resolution of port)
                 * unicast packets.
                 */
-               __set_bit(BNX2X_ACCEPT_UNMATCHED, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_UNMATCHED, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
 
                /* internal switching mode */
-               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
 
                if (IS_MF_SI(bp))
-                       __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &tx_accept_flags);
+                       __set_bit(BNX2X_ACCEPT_ALL_UNICAST, tx_accept_flags);
                else
-                       __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
+                       __set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
 
                break;
        default:
-               BNX2X_ERR("Unknown rx_mode: %d\n", bp->rx_mode);
-               return;
+               BNX2X_ERR("Unknown rx_mode: %d\n", rx_mode);
+               return -EINVAL;
        }
 
+       /* Set ACCEPT_ANY_VLAN as we do not enable filtering by VLAN */
        if (bp->rx_mode != BNX2X_RX_MODE_NONE) {
-               __set_bit(BNX2X_ACCEPT_ANY_VLAN, &rx_accept_flags);
-               __set_bit(BNX2X_ACCEPT_ANY_VLAN, &tx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
+               __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
        }
 
+       return 0;
+}
+
+/* called with netif_addr_lock_bh() */
+int bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+{
+       unsigned long rx_mode_flags = 0, ramrod_flags = 0;
+       unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
+       int rc;
+
+       if (!NO_FCOE(bp))
+               /* Configure rx_mode of FCoE Queue */
+               __set_bit(BNX2X_RX_MODE_FCOE_ETH, &rx_mode_flags);
+
+       rc = bnx2x_fill_accept_flags(bp, bp->rx_mode, &rx_accept_flags,
+                                    &tx_accept_flags);
+       if (rc)
+               return rc;
+
        __set_bit(RAMROD_RX, &ramrod_flags);
        __set_bit(RAMROD_TX, &ramrod_flags);
 
-       bnx2x_set_q_rx_mode(bp, bp->fp->cl_id, rx_mode_flags, rx_accept_flags,
-                           tx_accept_flags, ramrod_flags);
+       return bnx2x_set_q_rx_mode(bp, bp->fp->cl_id, rx_mode_flags,
+                                  rx_accept_flags, tx_accept_flags,
+                                  ramrod_flags);
 }
 
 static void bnx2x_init_internal_common(struct bnx2x *bp)
@@ -5699,6 +5933,13 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
                cids[cos] = fp->txdata_ptr[cos]->cid;
        }
 
+       /* nothing more for vf to do here */
+       if (IS_VF(bp))
+               return;
+
+       bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
+                     fp->fw_sb_id, fp->igu_sb_id);
+       bnx2x_update_fpsb_idx(fp);
        bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, cids,
                             fp->max_cos, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
                             bnx2x_sp_mapping(bp, q_rdata), q_type);
@@ -5708,13 +5949,10 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
         */
        bnx2x_init_vlan_mac_fp_objs(fp, BNX2X_OBJ_TYPE_RX_TX);
 
-       DP(NETIF_MSG_IFUP, "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  fw_sb %d  igu_sb %d\n",
-                  fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
-                  fp->igu_sb_id);
-       bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
-                     fp->fw_sb_id, fp->igu_sb_id);
-
-       bnx2x_update_fpsb_idx(fp);
+       DP(NETIF_MSG_IFUP,
+          "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  fw_sb %d  igu_sb %d\n",
+          fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
+          fp->igu_sb_id);
 }
 
 static void bnx2x_init_tx_ring_one(struct bnx2x_fp_txdata *txdata)
@@ -5786,17 +6024,22 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
 
        for_each_eth_queue(bp, i)
                bnx2x_init_eth_fp(bp, i);
-       /* Initialize MOD_ABS interrupts */
-       bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
-                              bp->common.shmem_base, bp->common.shmem2_base,
-                              BP_PORT(bp));
+
        /* ensure status block indices were read */
        rmb();
+       bnx2x_init_rx_rings(bp);
+       bnx2x_init_tx_rings(bp);
+
+       if (IS_VF(bp))
+               return;
+
+       /* Initialize MOD_ABS interrupts */
+       bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
+                              bp->common.shmem_base, bp->common.shmem2_base,
+                              BP_PORT(bp));
 
        bnx2x_init_def_sb(bp);
        bnx2x_update_dsb_idx(bp);
-       bnx2x_init_rx_rings(bp);
-       bnx2x_init_tx_rings(bp);
        bnx2x_init_sp_ring(bp);
        bnx2x_init_eq_ring(bp);
        bnx2x_init_internal(bp, load_code);
@@ -6236,49 +6479,6 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
        REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
 }
 
-static void bnx2x_pretend_func(struct bnx2x *bp, u8 pretend_func_num)
-{
-       u32 offset = 0;
-
-       if (CHIP_IS_E1(bp))
-               return;
-       if (CHIP_IS_E1H(bp) && (pretend_func_num >= E1H_FUNC_MAX))
-               return;
-
-       switch (BP_ABS_FUNC(bp)) {
-       case 0:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F0;
-               break;
-       case 1:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F1;
-               break;
-       case 2:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F2;
-               break;
-       case 3:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F3;
-               break;
-       case 4:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F4;
-               break;
-       case 5:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F5;
-               break;
-       case 6:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F6;
-               break;
-       case 7:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F7;
-               break;
-       default:
-               return;
-       }
-
-       REG_WR(bp, offset, pretend_func_num);
-       REG_RD(bp, offset);
-       DP(NETIF_MSG_HW, "Pretending to func %d\n", pretend_func_num);
-}
-
 void bnx2x_pf_disable(struct bnx2x *bp)
 {
        u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
@@ -6322,7 +6522,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
        DP(NETIF_MSG_HW, "starting common init  func %d\n", BP_ABS_FUNC(bp));
 
        /*
-        * take the UNDI lock to protect undi_unload flow from accessing
+        * take the RESET lock to protect undi_unload flow from accessing
         * registers while we're resetting the chip
         */
        bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
@@ -6452,7 +6652,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
  *                 queues with "old" ILT addresses.
  *             c.  PF enable in the PGLC.
  *             d.  Clear the was_error of the PF in the PGLC. (could have
- *                 occured while driver was down)
+ *                 occurred while driver was down)
  *             e.  PF enable in the CFC (WEAK + STRONG)
  *             f.  Timers scan enable
  *     3.  PF driver unload flow:
@@ -6493,7 +6693,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
                /* Step 1: set zeroes to all ilt page entries with valid bit on
                 * Step 2: set the timers first/last ilt entry to point
                 * to the entire range to prevent ILT range error for 3rd/4th
-                * vnic (this code assumes existance of the vnic)
+                * vnic (this code assumes existence of the vnic)
                 *
                 * both steps performed by call to bnx2x_ilt_client_init_op()
                 * with dummy TM client
@@ -6510,7 +6710,6 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
                REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN_SEL, 1);
        }
 
-
        REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0);
        REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0);
 
@@ -6535,6 +6734,8 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_DMAE, PHASE_COMMON);
 
+       bnx2x_iov_init_dmae(bp);
+
        /* clean the DMAE memory */
        bp->dmae_ready = 1;
        bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8, 1);
@@ -6991,7 +7192,6 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
                }
        }
 
-
        /* If SPIO5 is set to generate interrupts, enable it for this port */
        val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
        if (val & MISC_SPIO_SPIO5) {
@@ -7020,15 +7220,14 @@ static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
        REG_WR_DMAE(bp, reg, wb_write, 2);
 }
 
-static void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func,
-                                  u8 idu_sb_id, bool is_Pf)
+void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf)
 {
        u32 data, ctl, cnt = 100;
        u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
        u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
        u32 igu_addr_ack = IGU_REG_CSTORM_TYPE_0_SB_CLEANUP + (idu_sb_id/32)*4;
        u32 sb_bit =  1 << (idu_sb_id%32);
-       u32 func_encode = func | (is_Pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
+       u32 func_encode = func | (is_pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
        u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + idu_sb_id;
 
        /* Not supported in BC mode */
@@ -7219,8 +7418,10 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
        /* FLR cleanup - hmmm */
        if (!CHIP_IS_E1x(bp)) {
                rc = bnx2x_pf_flr_clnup(bp);
-               if (rc)
+               if (rc) {
+                       bnx2x_fw_dump(bp);
                        return rc;
+               }
        }
 
        /* set MSI reconfigure capability */
@@ -7237,12 +7438,21 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
        ilt = BP_ILT(bp);
        cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
 
+       if (IS_SRIOV(bp))
+               cdu_ilt_start += BNX2X_FIRST_VF_CID/ILT_PAGE_CIDS;
+       cdu_ilt_start = bnx2x_iov_init_ilt(bp, cdu_ilt_start);
+
+       /* since BNX2X_FIRST_VF_CID > 0 the PF L2 cids precedes
+        * those of the VFs, so start line should be reset
+        */
+       cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
        for (i = 0; i < L2_ILT_LINES(bp); i++) {
                ilt->lines[cdu_ilt_start + i].page = bp->context[i].vcxt;
                ilt->lines[cdu_ilt_start + i].page_mapping =
                        bp->context[i].cxt_mapping;
                ilt->lines[cdu_ilt_start + i].size = bp->context[i].size;
        }
+
        bnx2x_ilt_init_op(bp, INITOP_SET);
 
        if (!CONFIGURE_NIC_MODE(bp)) {
@@ -7315,6 +7525,9 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_TM, init_phase);
        bnx2x_init_block(bp, BLOCK_DORQ, init_phase);
+
+       bnx2x_iov_init_dq(bp);
+
        bnx2x_init_block(bp, BLOCK_BRB1, init_phase);
        bnx2x_init_block(bp, BLOCK_PRS, init_phase);
        bnx2x_init_block(bp, BLOCK_TSDM, init_phase);
@@ -7523,10 +7736,6 @@ void bnx2x_free_mem(struct bnx2x *bp)
 {
        int i;
 
-       /* fastpath */
-       bnx2x_free_fp_mem(bp);
-       /* end of fastpath */
-
        BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
                       sizeof(struct host_sp_status_block));
 
@@ -7547,69 +7756,11 @@ void bnx2x_free_mem(struct bnx2x *bp)
 
        BNX2X_PCI_FREE(bp->eq_ring, bp->eq_mapping,
                       BCM_PAGE_SIZE * NUM_EQ_PAGES);
-}
-
-static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
-{
-       int num_groups;
-       int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
 
-       /* number of queues for statistics is number of eth queues + FCoE */
-       u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
-
-       /* Total number of FW statistics requests =
-        * 1 for port stats + 1 for PF stats + potential 1 for FCoE stats +
-        * num of queues
-        */
-       bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
-
-
-       /* Request is built from stats_query_header and an array of
-        * stats_query_cmd_group each of which contains
-        * STATS_QUERY_CMD_COUNT rules. The real number or requests is
-        * configured in the stats_query_header.
-        */
-       num_groups = ((bp->fw_stats_num) / STATS_QUERY_CMD_COUNT) +
-                    (((bp->fw_stats_num) % STATS_QUERY_CMD_COUNT) ? 1 : 0);
-
-       bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
-                       num_groups * sizeof(struct stats_query_cmd_group);
-
-       /* Data for statistics requests + stats_conter
-        *
-        * stats_counter holds per-STORM counters that are incremented
-        * when STORM has finished with the current request.
-        *
-        * memory for FCoE offloaded statistics are counted anyway,
-        * even if they will not be sent.
-        */
-       bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
-               sizeof(struct per_pf_stats) +
-               sizeof(struct fcoe_statistics_params) +
-               sizeof(struct per_queue_stats) * num_queue_stats +
-               sizeof(struct stats_counter);
-
-       BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
-                       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
-
-       /* Set shortcuts */
-       bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
-       bp->fw_stats_req_mapping = bp->fw_stats_mapping;
-
-       bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
-               ((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
-
-       bp->fw_stats_data_mapping = bp->fw_stats_mapping +
-                                  bp->fw_stats_req_sz;
-       return 0;
-
-alloc_mem_err:
-       BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
-                      bp->fw_stats_data_sz + bp->fw_stats_req_sz);
-       BNX2X_ERR("Can't allocate memory\n");
-       return -ENOMEM;
+       bnx2x_iov_free_mem(bp);
 }
 
+
 int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
 {
        if (!CHIP_IS_E1x(bp))
@@ -7655,10 +7806,6 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
        BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
                        sizeof(struct bnx2x_slowpath));
 
-       /* Allocated memory for FW statistics  */
-       if (bnx2x_alloc_fw_stats_mem(bp))
-               goto alloc_mem_err;
-
        /* Allocate memory for CDU context:
         * This memory is allocated separately and not in the generic ILT
         * functions because CDU differs in few aspects:
@@ -7687,6 +7834,9 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
        if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
                goto alloc_mem_err;
 
+       if (bnx2x_iov_alloc_mem(bp))
+               goto alloc_mem_err;
+
        /* Slow path ring */
        BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
 
@@ -7694,13 +7844,6 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
        BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
                        BCM_PAGE_SIZE * NUM_EQ_PAGES);
 
-
-       /* fastpath */
-       /* need to be done at the end, since it's self adjusting to amount
-        * of memory available for RSS queues
-        */
-       if (bnx2x_alloc_fp_mem(bp))
-               goto alloc_mem_err;
        return 0;
 
 alloc_mem_err:
@@ -7803,43 +7946,53 @@ int bnx2x_setup_leading(struct bnx2x *bp)
  *
  * In case of MSI-X it will also try to enable MSI-X.
  */
-void bnx2x_set_int_mode(struct bnx2x *bp)
+int bnx2x_set_int_mode(struct bnx2x *bp)
 {
+       int rc = 0;
+
+       if (IS_VF(bp) && int_mode != BNX2X_INT_MODE_MSIX)
+               return -EINVAL;
+
        switch (int_mode) {
-       case INT_MODE_MSI:
+       case BNX2X_INT_MODE_MSIX:
+               /* attempt to enable msix */
+               rc = bnx2x_enable_msix(bp);
+
+               /* msix attained */
+               if (!rc)
+                       return 0;
+
+               /* vfs use only msix */
+               if (rc && IS_VF(bp))
+                       return rc;
+
+               /* failed to enable multiple MSI-X */
+               BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
+                              bp->num_queues,
+                              1 + bp->num_cnic_queues);
+
+               /* falling through... */
+       case BNX2X_INT_MODE_MSI:
                bnx2x_enable_msi(bp);
+
                /* falling through... */
-       case INT_MODE_INTx:
+       case BNX2X_INT_MODE_INTX:
                bp->num_ethernet_queues = 1;
                bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
                BNX2X_DEV_INFO("set number of queues to 1\n");
                break;
        default:
-               /* if we can't use MSI-X we only need one fp,
-                * so try to enable MSI-X with the requested number of fp's
-                * and fallback to MSI or legacy INTx with one fp
-                */
-               if (bnx2x_enable_msix(bp) ||
-                   bp->flags & USING_SINGLE_MSIX_FLAG) {
-                       /* failed to enable multiple MSI-X */
-                       BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
-                                      bp->num_queues,
-                                      1 + bp->num_cnic_queues);
-
-                       bp->num_queues = 1 + bp->num_cnic_queues;
-
-                       /* Try to enable MSI */
-                       if (!(bp->flags & USING_SINGLE_MSIX_FLAG) &&
-                           !(bp->flags & DISABLE_MSI_FLAG))
-                               bnx2x_enable_msi(bp);
-               }
-               break;
+               BNX2X_DEV_INFO("unknown value in int_mode module parameter\n");
+               return -EINVAL;
        }
+       return 0;
 }
 
-/* must be called prioir to any HW initializations */
+/* must be called prior to any HW initializations */
 static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp)
 {
+       if (IS_SRIOV(bp))
+               return (BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)/ILT_PAGE_CIDS;
        return L2_ILT_LINES(bp);
 }
 
@@ -8222,8 +8375,8 @@ static void bnx2x_reset_func(struct bnx2x *bp)
 
        /* SP SB */
        REG_WR8(bp, BAR_CSTRORM_INTMEM +
-                  CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(func),
-                  SB_DISABLED);
+               CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(func),
+               SB_DISABLED);
 
        for (i = 0; i < XSTORM_SPQ_DATA_SIZE / 4; i++)
                REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_DATA_OFFSET(func),
@@ -8524,7 +8677,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
        }
 
        /* Give HW time to discard old tx messages */
-       usleep_range(1000, 1000);
+       usleep_range(1000, 2000);
 
        /* Clean all ETH MACs */
        rc = bnx2x_del_all_macs(bp, &bp->sp_objs[0].mac_obj, BNX2X_ETH_MAC,
@@ -8562,6 +8715,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
 
        netif_addr_unlock_bh(bp->dev);
 
+       bnx2x_iov_chip_cleanup(bp);
 
 
        /*
@@ -8947,7 +9101,7 @@ static int bnx2x_er_poll_igu_vq(struct bnx2x *bp)
                if (pend_bits == 0)
                        break;
 
-               usleep_range(1000, 1000);
+               usleep_range(1000, 2000);
        } while (cnt-- > 0);
 
        if (cnt <= 0) {
@@ -8964,8 +9118,7 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
        int cnt = 1000;
        u32 val = 0;
        u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2;
-               u32 tags_63_32 = 0;
-
+       u32 tags_63_32 = 0;
 
        /* Empty the Tetris buffer, wait for 1s */
        do {
@@ -8983,7 +9136,7 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
                    (pgl_exp_rom2 == 0xffffffff) &&
                    (!CHIP_IS_E3(bp) || (tags_63_32 == 0xffffffff)))
                        break;
-               usleep_range(1000, 1000);
+               usleep_range(1000, 2000);
        } while (cnt-- > 0);
 
        if (cnt <= 0) {
@@ -9016,7 +9169,7 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
        /* Wait for 1ms to empty GLUE and PCI-E core queues,
         * PSWHST, GRC and PSWRD Tetris buffer.
         */
-       usleep_range(1000, 1000);
+       usleep_range(1000, 2000);
 
        /* Prepare to chip reset: */
        /* MCP */
@@ -9299,8 +9452,10 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
 
        rtnl_lock();
 
-       if (!netif_running(bp->dev))
-               goto sp_rtnl_exit;
+       if (!netif_running(bp->dev)) {
+               rtnl_unlock();
+               return;
+       }
 
        /* if stop on error is defined no recovery flows should be executed */
 #ifdef BNX2X_STOP_ON_ERROR
@@ -9319,7 +9474,8 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
 
                bnx2x_parity_recover(bp);
 
-               goto sp_rtnl_exit;
+               rtnl_unlock();
+               return;
        }
 
        if (test_and_clear_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state)) {
@@ -9333,7 +9489,8 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
                bnx2x_nic_unload(bp, UNLOAD_NORMAL, true);
                bnx2x_nic_load(bp, LOAD_NORMAL);
 
-               goto sp_rtnl_exit;
+               rtnl_unlock();
+               return;
        }
 #ifdef BNX2X_STOP_ON_ERROR
 sp_rtnl_not_reset:
@@ -9351,13 +9508,33 @@ sp_rtnl_not_reset:
                DP(NETIF_MSG_HW, "fan failure detected. Unloading driver\n");
                netif_device_detach(bp->dev);
                bnx2x_close(bp->dev);
+               rtnl_unlock();
+               return;
+       }
+
+       if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_MCAST, &bp->sp_rtnl_state)) {
+               DP(BNX2X_MSG_SP,
+                  "sending set mcast vf pf channel message from rtnl sp-task\n");
+               bnx2x_vfpf_set_mcast(bp->dev);
+       }
+
+       if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+                              &bp->sp_rtnl_state)) {
+               DP(BNX2X_MSG_SP,
+                  "sending set storm rx mode vf pf channel message from rtnl sp-task\n");
+               bnx2x_vfpf_storm_rx_mode(bp);
        }
 
-sp_rtnl_exit:
+       /* work which needs rtnl lock not-taken (as it takes the lock itself and
+        * can be called from other contexts as well)
+        */
        rtnl_unlock();
-}
 
-/* end of nic load/unload */
+       /* enable SR-IOV if applicable */
+       if (IS_SRIOV(bp) && test_and_clear_bit(BNX2X_SP_RTNL_ENABLE_SRIOV,
+                                              &bp->sp_rtnl_state))
+               bnx2x_enable_sriov(bp);
+}
 
 static void bnx2x_period_task(struct work_struct *work)
 {
@@ -9394,43 +9571,13 @@ period_task_exit:
  * Init service functions
  */
 
-static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
+u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
 {
        u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0;
        u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base;
        return base + (BP_ABS_FUNC(bp)) * stride;
 }
 
-static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp)
-{
-       u32 reg = bnx2x_get_pretend_reg(bp);
-
-       /* Flush all outstanding writes */
-       mmiowb();
-
-       /* Pretend to be function 0 */
-       REG_WR(bp, reg, 0);
-       REG_RD(bp, reg);        /* Flush the GRC transaction (in the chip) */
-
-       /* From now we are in the "like-E1" mode */
-       bnx2x_int_disable(bp);
-
-       /* Flush all outstanding writes */
-       mmiowb();
-
-       /* Restore the original function */
-       REG_WR(bp, reg, BP_ABS_FUNC(bp));
-       REG_RD(bp, reg);
-}
-
-static inline void bnx2x_undi_int_disable(struct bnx2x *bp)
-{
-       if (CHIP_IS_E1(bp))
-               bnx2x_int_disable(bp);
-       else
-               bnx2x_undi_int_disable_e1h(bp);
-}
-
 static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
                                        struct bnx2x_mac_vals *vals)
 {
@@ -9658,11 +9805,13 @@ static int bnx2x_prev_unload_uncommon(struct bnx2x *bp)
        if (bnx2x_prev_is_path_marked(bp))
                return bnx2x_prev_mcp_done(bp);
 
+       BNX2X_DEV_INFO("Path is unmarked\n");
+
        /* If function has FLR capabilities, and existing FW version matches
         * the one required, then FLR will be sufficient to clean any residue
         * left by previous driver
         */
-       rc = bnx2x_test_firmware_version(bp, false);
+       rc = bnx2x_nic_load_analyze_req(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION);
 
        if (!rc) {
                /* fw version is good */
@@ -9718,7 +9867,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                /* Check if the UNDI driver was previously loaded
                 * UNDI driver initializes CID offset for normal bell to 0x7
                 */
-               reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1);
                if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_DORQ) {
                        tmp_reg = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
                        if (tmp_reg == 0x7) {
@@ -9726,6 +9874,8 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                                prev_undi = true;
                                /* clear the UNDI indication */
                                REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
+                               /* clear possible idle check errors */
+                               REG_RD(bp, NIG_REG_NIG_INT_STS_CLR_0);
                        }
                }
                /* wait until BRB is empty */
@@ -9792,7 +9942,8 @@ static void bnx2x_prev_interrupted_dmae(struct bnx2x *bp)
        if (!CHIP_IS_E1x(bp)) {
                u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
                if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
-                       BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing");
+                       DP(BNX2X_MSG_SP,
+                          "'was error' bit was found to be set in pglueb upon startup. Clearing\n");
                        REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
                               1 << BP_FUNC(bp));
                }
@@ -9834,7 +9985,6 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
                REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0);
        }
 
-
        do {
                /* Lock MCP using an unload request */
                fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0);
@@ -10401,10 +10551,10 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
 
 static void bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
 {
-       mac_hi = cpu_to_be16(mac_hi);
-       mac_lo = cpu_to_be32(mac_lo);
-       memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
-       memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
+       __be16 mac_hi_be = cpu_to_be16(mac_hi);
+       __be32 mac_lo_be = cpu_to_be32(mac_lo);
+       memcpy(mac_buf, &mac_hi_be, sizeof(mac_hi_be));
+       memcpy(mac_buf + sizeof(mac_hi_be), &mac_lo_be, sizeof(mac_lo_be));
 }
 
 static void bnx2x_get_port_hwinfo(struct bnx2x *bp)
@@ -10440,6 +10590,13 @@ static void bnx2x_get_port_hwinfo(struct bnx2x *bp)
        bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
                   (config & PORT_FEATURE_WOL_ENABLED));
 
+       if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+           PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE && !IS_MF(bp))
+               bp->flags |= NO_ISCSI_FLAG;
+       if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+           PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI && !(IS_MF(bp)))
+               bp->flags |= NO_FCOE_FLAG;
+
        BNX2X_DEV_INFO("lane_config 0x%08x  speed_cap_mask0 0x%08x  link_config0 0x%08x\n",
                       bp->link_params.lane_config,
                       bp->link_params.speed_cap_mask[0],
@@ -10547,21 +10704,21 @@ static void bnx2x_get_fcoe_info(struct bnx2x *bp)
                /* Port info */
                bp->cnic_eth_dev.fcoe_wwn_port_name_hi =
                        SHMEM_RD(bp,
-                               dev_info.port_hw_config[port].
+                                dev_info.port_hw_config[port].
                                 fcoe_wwn_port_name_upper);
                bp->cnic_eth_dev.fcoe_wwn_port_name_lo =
                        SHMEM_RD(bp,
-                               dev_info.port_hw_config[port].
+                                dev_info.port_hw_config[port].
                                 fcoe_wwn_port_name_lower);
 
                /* Node info */
                bp->cnic_eth_dev.fcoe_wwn_node_name_hi =
                        SHMEM_RD(bp,
-                               dev_info.port_hw_config[port].
+                                dev_info.port_hw_config[port].
                                 fcoe_wwn_node_name_upper);
                bp->cnic_eth_dev.fcoe_wwn_node_name_lo =
                        SHMEM_RD(bp,
-                               dev_info.port_hw_config[port].
+                                dev_info.port_hw_config[port].
                                 fcoe_wwn_node_name_lower);
        } else if (!IS_MF_SD(bp)) {
                /*
@@ -10659,7 +10816,7 @@ static void bnx2x_get_cnic_mac_hwinfo(struct bnx2x *bp)
                        /* Zero primary MAC configuration */
                        memset(bp->dev->dev_addr, 0, ETH_ALEN);
 
-               if (IS_MF_FCOE_AFEX(bp))
+               if (IS_MF_FCOE_AFEX(bp) || IS_MF_FCOE_SD(bp))
                        /* use FIP MAC as primary MAC */
                        memcpy(bp->dev->dev_addr, fip_mac, ETH_ALEN);
 
@@ -10722,7 +10879,6 @@ static void bnx2x_get_mac_hwinfo(struct bnx2x *bp)
        }
 
        memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
-       memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
 
        if (!bnx2x_is_valid_ether_addr(bp, bp->dev->dev_addr))
                dev_err(&bp->pdev->dev,
@@ -10787,7 +10943,7 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
 
                        while (tout && REG_RD(bp, IGU_REG_RESET_MEMORIES)) {
                                tout--;
-                               usleep_range(1000, 1000);
+                               usleep_range(1000, 2000);
                        }
 
                        if (REG_RD(bp, IGU_REG_RESET_MEMORIES)) {
@@ -11125,9 +11281,13 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
        INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
        INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
-       rc = bnx2x_get_hwinfo(bp);
-       if (rc)
-               return rc;
+       if (IS_PF(bp)) {
+               rc = bnx2x_get_hwinfo(bp);
+               if (rc)
+                       return rc;
+       } else {
+               random_ether_addr(bp->dev->dev_addr);
+       }
 
        bnx2x_set_modes_bitmap(bp);
 
@@ -11140,7 +11300,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        func = BP_FUNC(bp);
 
        /* need to reset chip if undi was active */
-       if (!BP_NOMCP(bp)) {
+       if (IS_PF(bp) && !BP_NOMCP(bp)) {
                /* init fw_seq */
                bp->fw_seq =
                        SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
@@ -11177,6 +11337,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        bp->mrrs = mrrs;
 
        bp->tx_ring_size = IS_MF_FCOE_AFEX(bp) ? 0 : MAX_TX_AVAIL;
+       if (IS_VF(bp))
+               bp->rx_ring_size = MAX_RX_AVAIL;
 
        /* make sure that the numbers are in the right granularity */
        bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR;
@@ -11205,12 +11367,18 @@ static int bnx2x_init_bp(struct bnx2x *bp)
                bp->cnic_base_cl_id = FP_SB_MAX_E2;
 
        /* multiple tx priority */
-       if (CHIP_IS_E1x(bp))
+       if (IS_VF(bp))
+               bp->max_cos = 1;
+       else if (CHIP_IS_E1x(bp))
                bp->max_cos = BNX2X_MULTI_TX_COS_E1X;
-       if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
+       else if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
                bp->max_cos = BNX2X_MULTI_TX_COS_E2_E3A0;
-       if (CHIP_IS_E3B0(bp))
+       else if (CHIP_IS_E3B0(bp))
                bp->max_cos = BNX2X_MULTI_TX_COS_E3B0;
+       else
+               BNX2X_ERR("unknown chip %x revision %x\n",
+                         CHIP_NUM(bp), CHIP_REV(bp));
+       BNX2X_DEV_INFO("set bp->max_cos to %d\n", bp->max_cos);
 
        /* We need at least one default status block for slow-path events,
         * second status block for the L2 queue, and a third status block for
@@ -11234,6 +11402,26 @@ static int bnx2x_init_bp(struct bnx2x *bp)
  * net_device service functions
  */
 
+static int bnx2x_open_epilog(struct bnx2x *bp)
+{
+       /* Enable sriov via delayed work. This must be done via delayed work
+        * because it causes the probe of the vf devices to be run, which invoke
+        * register_netdevice which must have rtnl lock taken. As we are holding
+        * the lock right now, that could only work if the probe would not take
+        * the lock. However, as the probe of the vf may be called from other
+        * contexts as well (such as passthrough to vm failes) it can't assume
+        * the lock is being held for it. Using delayed work here allows the
+        * probe code to simply take the lock (i.e. wait for it to be released
+        * if it is being held).
+        */
+       smp_mb__before_clear_bit();
+       set_bit(BNX2X_SP_RTNL_ENABLE_SRIOV, &bp->sp_rtnl_state);
+       smp_mb__after_clear_bit();
+       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+
+       return 0;
+}
+
 /* called with rtnl_lock */
 static int bnx2x_open(struct net_device *dev)
 {
@@ -11241,6 +11429,7 @@ static int bnx2x_open(struct net_device *dev)
        bool global = false;
        int other_engine = BP_PATH(bp) ? 0 : 1;
        bool other_load_status, load_status;
+       int rc;
 
        bp->stats_init = true;
 
@@ -11248,53 +11437,57 @@ static int bnx2x_open(struct net_device *dev)
 
        bnx2x_set_power_state(bp, PCI_D0);
 
-       other_load_status = bnx2x_get_load_status(bp, other_engine);
-       load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
-
-       /*
-        * If parity had happen during the unload, then attentions
+       /* If parity had happen during the unload, then attentions
         * and/or RECOVERY_IN_PROGRES may still be set. In this case we
         * want the first function loaded on the current engine to
         * complete the recovery.
+        * Parity recovery is only relevant for PF driver.
         */
-       if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
-           bnx2x_chk_parity_attn(bp, &global, true))
-               do {
-                       /*
-                        * If there are attentions and they are in a global
-                        * blocks, set the GLOBAL_RESET bit regardless whether
-                        * it will be this function that will complete the
-                        * recovery or not.
-                        */
-                       if (global)
-                               bnx2x_set_reset_global(bp);
+       if (IS_PF(bp)) {
+               other_load_status = bnx2x_get_load_status(bp, other_engine);
+               load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
+               if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
+                   bnx2x_chk_parity_attn(bp, &global, true)) {
+                       do {
+                               /* If there are attentions and they are in a
+                                * global blocks, set the GLOBAL_RESET bit
+                                * regardless whether it will be this function
+                                * that will complete the recovery or not.
+                                */
+                               if (global)
+                                       bnx2x_set_reset_global(bp);
 
-                       /*
-                        * Only the first function on the current engine should
-                        * try to recover in open. In case of attentions in
-                        * global blocks only the first in the chip should try
-                        * to recover.
-                        */
-                       if ((!load_status &&
-                            (!global || !other_load_status)) &&
-                           bnx2x_trylock_leader_lock(bp) &&
-                           !bnx2x_leader_reset(bp)) {
-                               netdev_info(bp->dev, "Recovered in open\n");
-                               break;
-                       }
+                               /* Only the first function on the current
+                                * engine should try to recover in open. In case
+                                * of attentions in global blocks only the first
+                                * in the chip should try to recover.
+                                */
+                               if ((!load_status &&
+                                    (!global || !other_load_status)) &&
+                                     bnx2x_trylock_leader_lock(bp) &&
+                                     !bnx2x_leader_reset(bp)) {
+                                       netdev_info(bp->dev,
+                                                   "Recovered in open\n");
+                                       break;
+                               }
 
-                       /* recovery has failed... */
-                       bnx2x_set_power_state(bp, PCI_D3hot);
-                       bp->recovery_state = BNX2X_RECOVERY_FAILED;
+                               /* recovery has failed... */
+                               bnx2x_set_power_state(bp, PCI_D3hot);
+                               bp->recovery_state = BNX2X_RECOVERY_FAILED;
 
-                       BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
-                                 "If you still see this message after a few retries then power cycle is required.\n");
+                               BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
+                                         "If you still see this message after a few retries then power cycle is required.\n");
 
-                       return -EAGAIN;
-               } while (0);
+                               return -EAGAIN;
+                       } while (0);
+               }
+       }
 
        bp->recovery_state = BNX2X_RECOVERY_DONE;
-       return bnx2x_nic_load(bp, LOAD_OPEN);
+       rc = bnx2x_nic_load(bp, LOAD_OPEN);
+       if (rc)
+               return rc;
+       return bnx2x_open_epilog(bp);
 }
 
 /* called with rtnl_lock */
@@ -11428,7 +11621,6 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
        return rc;
 }
 
-
 /* If bp->state is OPEN, should be called with netif_addr_lock_bh() */
 void bnx2x_set_rx_mode(struct net_device *dev)
 {
@@ -11449,12 +11641,25 @@ void bnx2x_set_rx_mode(struct net_device *dev)
                  CHIP_IS_E1(bp)))
                rx_mode = BNX2X_RX_MODE_ALLMULTI;
        else {
-               /* some multicasts */
-               if (bnx2x_set_mc_list(bp) < 0)
-                       rx_mode = BNX2X_RX_MODE_ALLMULTI;
+               if (IS_PF(bp)) {
+                       /* some multicasts */
+                       if (bnx2x_set_mc_list(bp) < 0)
+                               rx_mode = BNX2X_RX_MODE_ALLMULTI;
 
-               if (bnx2x_set_uc_list(bp) < 0)
-                       rx_mode = BNX2X_RX_MODE_PROMISC;
+                       if (bnx2x_set_uc_list(bp) < 0)
+                               rx_mode = BNX2X_RX_MODE_PROMISC;
+               } else {
+                       /* configuring mcast to a vf involves sleeping (when we
+                        * wait for the pf's response). Since this function is
+                        * called from non sleepable context we must schedule
+                        * a work item for this purpose
+                        */
+                       smp_mb__before_clear_bit();
+                       set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
+                               &bp->sp_rtnl_state);
+                       smp_mb__after_clear_bit();
+                       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+               }
        }
 
        bp->rx_mode = rx_mode;
@@ -11468,7 +11673,20 @@ void bnx2x_set_rx_mode(struct net_device *dev)
                return;
        }
 
-       bnx2x_set_storm_rx_mode(bp);
+       if (IS_PF(bp)) {
+               bnx2x_set_storm_rx_mode(bp);
+       } else {
+               /* configuring rx mode to storms in a vf involves sleeping (when
+                * we wait for the pf's response). Since this function is
+                * called from non sleepable context we must schedule
+                * a work item for this purpose
+                */
+               smp_mb__before_clear_bit();
+               set_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+                       &bp->sp_rtnl_state);
+               smp_mb__after_clear_bit();
+               schedule_delayed_work(&bp->sp_rtnl_task, 0);
+       }
 }
 
 /* called with rtnl_lock */
@@ -11571,7 +11789,9 @@ static const struct net_device_ops bnx2x_netdev_ops = {
        .ndo_poll_controller    = poll_bnx2x,
 #endif
        .ndo_setup_tc           = bnx2x_setup_tc,
-
+#ifdef CONFIG_BNX2X_SRIOV
+       .ndo_set_vf_mac         = bnx2x_set_vf_mac,
+#endif
 #ifdef NETDEV_FCOE_WWNN
        .ndo_fcoe_get_wwn       = bnx2x_fcoe_get_wwn,
 #endif
@@ -11595,10 +11815,9 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp)
        return 0;
 }
 
-static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
-                         unsigned long board_type)
+static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
+                         struct net_device *dev, unsigned long board_type)
 {
-       struct bnx2x *bp;
        int rc;
        u32 pci_cfg_dword;
        bool chip_is_e1x = (board_type == BCM57710 ||
@@ -11606,11 +11825,9 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
                            board_type == BCM57711E);
 
        SET_NETDEV_DEV(dev, &pdev->dev);
-       bp = netdev_priv(dev);
 
        bp->dev = dev;
        bp->pdev = pdev;
-       bp->flags = 0;
 
        rc = pci_enable_device(pdev);
        if (rc) {
@@ -11626,9 +11843,8 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
                goto err_out_disable;
        }
 
-       if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
-               dev_err(&bp->pdev->dev, "Cannot find second PCI device"
-                      " base address, aborting\n");
+       if (IS_PF(bp) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+               dev_err(&bp->pdev->dev, "Cannot find second PCI device base address, aborting\n");
                rc = -ENODEV;
                goto err_out_disable;
        }
@@ -11653,12 +11869,14 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
                pci_save_state(pdev);
        }
 
-       bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (bp->pm_cap == 0) {
-               dev_err(&bp->pdev->dev,
-                       "Cannot find power management capability, aborting\n");
-               rc = -EIO;
-               goto err_out_release;
+       if (IS_PF(bp)) {
+               bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+               if (bp->pm_cap == 0) {
+                       dev_err(&bp->pdev->dev,
+                               "Cannot find power management capability, aborting\n");
+                       rc = -EIO;
+                       goto err_out_release;
+               }
        }
 
        if (!pci_is_pcie(pdev)) {
@@ -11690,13 +11908,14 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
         * support Physical Device Assignment where kernel BDF maybe arbitrary
         * (depending on hypervisor).
         */
-       if (chip_is_e1x)
+       if (chip_is_e1x) {
                bp->pf_num = PCI_FUNC(pdev->devfn);
-       else {/* chip is E2/3*/
+       } else {
+               /* chip is E2/3*/
                pci_read_config_dword(bp->pdev,
                                      PCICFG_ME_REGISTER, &pci_cfg_dword);
                bp->pf_num = (u8)((pci_cfg_dword & ME_REG_ABS_PF_NUM) >>
-                   ME_REG_ABS_PF_NUM_SHIFT);
+                                 ME_REG_ABS_PF_NUM_SHIFT);
        }
        BNX2X_DEV_INFO("me reg PF num: %d\n", bp->pf_num);
 
@@ -11709,25 +11928,28 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
         * Clean the following indirect addresses for all functions since it
         * is not used by the driver.
         */
-       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+       if (IS_PF(bp)) {
+               REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+
+               if (chip_is_e1x) {
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+               }
 
-       if (chip_is_e1x) {
-               REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
-               REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
-               REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
-               REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+               /* Enable internal target-read (in case we are probed after PF
+                * FLR). Must be done prior to any BAR read access. Only for
+                * 57712 and up
+                */
+               if (!chip_is_e1x)
+                       REG_WR(bp,
+                              PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
        }
 
-       /*
-        * Enable internal target-read (in case we are probed after PF FLR).
-        * Must be done prior to any BAR read access. Only for 57712 and up
-        */
-       if (!chip_is_e1x)
-               REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
-
        dev->watchdog_timeo = TX_TIMEOUT;
 
        dev->netdev_ops = &bnx2x_netdev_ops;
@@ -11778,8 +12000,9 @@ err_out:
 
 static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width, int *speed)
 {
-       u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+       u32 val = 0;
 
+       pci_read_config_dword(bp->pdev, PCICFG_LINK_CONTROL, &val);
        *width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
 
        /* return value of 1=2.5GHz 2=5GHz */
@@ -11792,7 +12015,7 @@ static int bnx2x_check_firmware(struct bnx2x *bp)
        struct bnx2x_fw_file_hdr *fw_hdr;
        struct bnx2x_fw_file_section *sections;
        u32 offset, len, num_ops;
-       u16 *ops_offsets;
+       __be16 *ops_offsets;
        int i;
        const u8 *fw_ver;
 
@@ -11817,7 +12040,7 @@ static int bnx2x_check_firmware(struct bnx2x *bp)
 
        /* Likewise for the init_ops offsets */
        offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset);
-       ops_offsets = (u16 *)(firmware->data + offset);
+       ops_offsets = (__force __be16 *)(firmware->data + offset);
        num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op);
 
        for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
@@ -12044,8 +12267,12 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
 {
        int cid_count = BNX2X_L2_MAX_CID(bp);
 
+       if (IS_SRIOV(bp))
+               cid_count += BNX2X_VF_CIDS;
+
        if (CNIC_SUPPORT(bp))
                cid_count += CNIC_CID_MAX;
+
        return roundup(cid_count, QM_CID_ROUND);
 }
 
@@ -12056,10 +12283,10 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
  *
  */
 static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
-                                    int cnic_cnt)
+                                    int cnic_cnt, bool is_vf)
 {
-       int pos;
-       u16 control;
+       int pos, index;
+       u16 control = 0;
 
        pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
 
@@ -12067,85 +12294,114 @@ static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
         * If MSI-X is not supported - return number of SBs needed to support
         * one fast path queue: one FP queue + SB for CNIC
         */
-       if (!pos)
+       if (!pos) {
+               dev_info(&pdev->dev, "no msix capability found\n");
                return 1 + cnic_cnt;
+       }
+       dev_info(&pdev->dev, "msix capability found\n");
 
        /*
         * The value in the PCI configuration space is the index of the last
         * entry, namely one less than the actual size of the table, which is
         * exactly what we want to return from this function: number of all SBs
         * without the default SB.
+        * For VFs there is no default SB, then we return (index+1).
         */
        pci_read_config_word(pdev, pos  + PCI_MSI_FLAGS, &control);
-       return control & PCI_MSIX_FLAGS_QSIZE;
-}
 
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *);
+       index = control & PCI_MSIX_FLAGS_QSIZE;
 
-static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       struct net_device *dev = NULL;
-       struct bnx2x *bp;
-       int pcie_width, pcie_speed;
-       int rc, max_non_def_sbs;
-       int rx_count, tx_count, rss_count, doorbell_size;
-       int cnic_cnt;
-       /*
-        * An estimated maximum supported CoS number according to the chip
-        * version.
-        * We will try to roughly estimate the maximum number of CoSes this chip
-        * may support in order to minimize the memory allocated for Tx
-        * netdev_queue's. This number will be accurately calculated during the
-        * initialization of bp->max_cos based on the chip versions AND chip
-        * revision in the bnx2x_init_bp().
-        */
-       u8 max_cos_est = 0;
+       return is_vf ? index + 1 : index;
+}
 
-       switch (ent->driver_data) {
+static int set_max_cos_est(int chip_id)
+{
+       switch (chip_id) {
        case BCM57710:
        case BCM57711:
        case BCM57711E:
-               max_cos_est = BNX2X_MULTI_TX_COS_E1X;
-               break;
-
+               return BNX2X_MULTI_TX_COS_E1X;
        case BCM57712:
        case BCM57712_MF:
-               max_cos_est = BNX2X_MULTI_TX_COS_E2_E3A0;
-               break;
-
+       case BCM57712_VF:
+               return BNX2X_MULTI_TX_COS_E2_E3A0;
        case BCM57800:
        case BCM57800_MF:
+       case BCM57800_VF:
        case BCM57810:
        case BCM57810_MF:
-       case BCM57840_O:
        case BCM57840_4_10:
        case BCM57840_2_20:
+       case BCM57840_O:
        case BCM57840_MFO:
+       case BCM57810_VF:
        case BCM57840_MF:
+       case BCM57840_VF:
        case BCM57811:
        case BCM57811_MF:
-               max_cos_est = BNX2X_MULTI_TX_COS_E3B0;
-               break;
-
+       case BCM57811_VF:
+               return BNX2X_MULTI_TX_COS_E3B0;
+               return 1;
        default:
-               pr_err("Unknown board_type (%ld), aborting\n",
-                          ent->driver_data);
+               pr_err("Unknown board_type (%d), aborting\n", chip_id);
                return -ENODEV;
        }
+}
 
-       cnic_cnt = 1;
-       max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt);
+static int set_is_vf(int chip_id)
+{
+       switch (chip_id) {
+       case BCM57712_VF:
+       case BCM57800_VF:
+       case BCM57810_VF:
+       case BCM57840_VF:
+       case BCM57811_VF:
+               return true;
+       default:
+               return false;
+       }
+}
 
-       WARN_ON(!max_non_def_sbs);
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
+
+static int bnx2x_init_one(struct pci_dev *pdev,
+                                   const struct pci_device_id *ent)
+{
+       struct net_device *dev = NULL;
+       struct bnx2x *bp;
+       int pcie_width, pcie_speed;
+       int rc, max_non_def_sbs;
+       int rx_count, tx_count, rss_count, doorbell_size;
+       int max_cos_est;
+       bool is_vf;
+       int cnic_cnt;
+
+       /* An estimated maximum supported CoS number according to the chip
+        * version.
+        * We will try to roughly estimate the maximum number of CoSes this chip
+        * may support in order to minimize the memory allocated for Tx
+        * netdev_queue's. This number will be accurately calculated during the
+        * initialization of bp->max_cos based on the chip versions AND chip
+        * revision in the bnx2x_init_bp().
+        */
+       max_cos_est = set_max_cos_est(ent->driver_data);
+       if (max_cos_est < 0)
+               return max_cos_est;
+       is_vf = set_is_vf(ent->driver_data);
+       cnic_cnt = is_vf ? 0 : 1;
+
+       max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt, is_vf);
 
        /* Maximum number of RSS queues: one IGU SB goes to CNIC */
-       rss_count = max_non_def_sbs - cnic_cnt;
+       rss_count = is_vf ? 1 : max_non_def_sbs - cnic_cnt;
+
+       if (rss_count < 1)
+               return -EINVAL;
 
        /* Maximum number of netdev Rx queues: RSS + FCoE L2 */
        rx_count = rss_count + cnic_cnt;
 
-       /*
-        * Maximum number of netdev Tx queues:
+       /* Maximum number of netdev Tx queues:
         * Maximum TSS queues * Maximum supported number of CoS  + FCoE L2
         */
        tx_count = rss_count * max_cos_est + cnic_cnt;
@@ -12157,42 +12413,55 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        bp = netdev_priv(dev);
 
+       bp->flags = 0;
+       if (is_vf)
+               bp->flags |= IS_VF_FLAG;
+
        bp->igu_sb_cnt = max_non_def_sbs;
+       bp->igu_base_addr = IS_VF(bp) ? PXP_VF_ADDR_IGU_START : BAR_IGU_INTMEM;
        bp->msg_enable = debug;
        bp->cnic_support = cnic_cnt;
        bp->cnic_probe = bnx2x_cnic_probe;
 
        pci_set_drvdata(pdev, dev);
 
-       rc = bnx2x_init_dev(pdev, dev, ent->driver_data);
+       rc = bnx2x_init_dev(bp, pdev, dev, ent->driver_data);
        if (rc < 0) {
                free_netdev(dev);
                return rc;
        }
 
+       BNX2X_DEV_INFO("This is a %s function\n",
+                      IS_PF(bp) ? "physical" : "virtual");
        BNX2X_DEV_INFO("Cnic support is %s\n", CNIC_SUPPORT(bp) ? "on" : "off");
-       BNX2X_DEV_INFO("max_non_def_sbs %d\n", max_non_def_sbs);
-
+       BNX2X_DEV_INFO("Max num of status blocks %d\n", max_non_def_sbs);
        BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n",
-                         tx_count, rx_count);
+                      tx_count, rx_count);
 
        rc = bnx2x_init_bp(bp);
        if (rc)
                goto init_one_exit;
 
-       /*
-        * Map doorbels here as we need the real value of bp->max_cos which
-        * is initialized in bnx2x_init_bp().
+       /* Map doorbells here as we need the real value of bp->max_cos which
+        * is initialized in bnx2x_init_bp() to determine the number of
+        * l2 connections.
         */
-       doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
-       if (doorbell_size > pci_resource_len(pdev, 2)) {
-               dev_err(&bp->pdev->dev,
-                       "Cannot map doorbells, bar size too small, aborting\n");
-               rc = -ENOMEM;
-               goto init_one_exit;
+       if (IS_VF(bp)) {
+               bnx2x_vf_map_doorbells(bp);
+               rc = bnx2x_vf_pci_alloc(bp);
+               if (rc)
+                       goto init_one_exit;
+       } else {
+               doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
+               if (doorbell_size > pci_resource_len(pdev, 2)) {
+                       dev_err(&bp->pdev->dev,
+                               "Cannot map doorbells, bar size too small, aborting\n");
+                       rc = -ENOMEM;
+                       goto init_one_exit;
+               }
+               bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
+                                               doorbell_size);
        }
-       bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
-                                       doorbell_size);
        if (!bp->doorbells) {
                dev_err(&bp->pdev->dev,
                        "Cannot map doorbell space, aborting\n");
@@ -12200,8 +12469,25 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto init_one_exit;
        }
 
+       if (IS_VF(bp)) {
+               rc = bnx2x_vfpf_acquire(bp, tx_count, rx_count);
+               if (rc)
+                       goto init_one_exit;
+       }
+
+       /* Enable SRIOV if capability found in configuration space.
+        * Once the generic SR-IOV framework makes it in from the
+        * pci tree this will be revised, to allow dynamic control
+        * over the number of VFs. Right now, change the num of vfs
+        * param below to enable SR-IOV.
+        */
+       rc = bnx2x_iov_init_one(bp, int_mode, 0/*num vfs*/);
+       if (rc)
+               goto init_one_exit;
+
        /* calc qm_cid_count */
        bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
+       BNX2X_DEV_INFO("qm_cid_count %d\n", bp->qm_cid_count);
 
        /* disable FCOE L2 queue for E1x*/
        if (CHIP_IS_E1x(bp))
@@ -12223,13 +12509,20 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Configure interrupt mode: try to enable MSI-X/MSI if
         * needed.
         */
-       bnx2x_set_int_mode(bp);
+       rc = bnx2x_set_int_mode(bp);
+       if (rc) {
+               dev_err(&pdev->dev, "Cannot set interrupts\n");
+               goto init_one_exit;
+       }
+       BNX2X_DEV_INFO("set interrupts successfully\n");
 
+       /* register the net device */
        rc = register_netdev(dev);
        if (rc) {
                dev_err(&pdev->dev, "Cannot register net device\n");
                goto init_one_exit;
        }
+       BNX2X_DEV_INFO("device name after netdev register %s\n", dev->name);
 
 
        if (!NO_FCOE(bp)) {
@@ -12240,6 +12533,8 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
+       BNX2X_DEV_INFO("got pcie width %d and speed %d\n",
+                      pcie_width, pcie_speed);
 
        BNX2X_DEV_INFO(
                "%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
@@ -12257,7 +12552,7 @@ init_one_exit:
        if (bp->regview)
                iounmap(bp->regview);
 
-       if (bp->doorbells)
+       if (IS_PF(bp) && bp->doorbells)
                iounmap(bp->doorbells);
 
        free_netdev(dev);
@@ -12297,25 +12592,37 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
        unregister_netdev(dev);
 
        /* Power on: we can't let PCI layer write to us while we are in D3 */
-       bnx2x_set_power_state(bp, PCI_D0);
+       if (IS_PF(bp))
+               bnx2x_set_power_state(bp, PCI_D0);
 
        /* Disable MSI/MSI-X */
        bnx2x_disable_msi(bp);
 
        /* Power off */
-       bnx2x_set_power_state(bp, PCI_D3hot);
+       if (IS_PF(bp))
+               bnx2x_set_power_state(bp, PCI_D3hot);
 
        /* Make sure RESET task is not scheduled before continuing */
        cancel_delayed_work_sync(&bp->sp_rtnl_task);
 
+       bnx2x_iov_remove_one(bp);
+
+       /* send message via vfpf channel to release the resources of this vf */
+       if (IS_VF(bp))
+               bnx2x_vfpf_release(bp);
+
        if (bp->regview)
                iounmap(bp->regview);
 
-       if (bp->doorbells)
-               iounmap(bp->doorbells);
-
-       bnx2x_release_firmware(bp);
+       /* for vf doorbells are part of the regview and were unmapped along with
+        * it. FW is only loaded by PF.
+        */
+       if (IS_PF(bp)) {
+               if (bp->doorbells)
+                       iounmap(bp->doorbells);
 
+               bnx2x_release_firmware(bp);
+       }
        bnx2x_free_mem_bp(bp);
 
        free_netdev(dev);
@@ -13103,4 +13410,36 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
        return cp;
 }
 
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
+{
+       struct bnx2x *bp = fp->bp;
+       u32 offset = BAR_USTRORM_INTMEM;
+
+       if (IS_VF(bp))
+               return bnx2x_vf_ustorm_prods_offset(bp, fp);
+       else if (!CHIP_IS_E1x(bp))
+               offset += USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
+       else
+               offset += USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
 
+       return offset;
+}
+
+/* called only on E1H or E2.
+ * When pretending to be PF, the pretend value is the function number 0...7
+ * When pretending to be VF, the pretend val is the PF-num:VF-valid:ABS-VFID
+ * combination
+ */
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
+{
+       u32 pretend_reg;
+
+       if (CHIP_IS_E1H(bp) && pretend_func_val >= E1H_FUNC_MAX)
+               return -1;
+
+       /* get my own pretend register */
+       pretend_reg = bnx2x_get_pretend_reg(bp);
+       REG_WR(bp, pretend_reg, pretend_func_val);
+       REG_RD(bp, pretend_reg);
+       return 0;
+}
index ddd5106ad2f9c5d8349dd89250dea3d28a944735..caf1aef651eb0bd38081887b68315597c2a5dc16 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_mfw_req.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2012 Broadcom Corporation
+ * Copyright (c) 2012-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index bc2f65b32649de1dcbd5b456a4b915fdea9d1ef3..791eb2d530111dd7e5fa8aa5c88adadf5e91ddb9 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_reg.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 /* [RW 28] The value sent to CM header in the case of CFC load error. */
 #define DORQ_REG_ERR_CMHEAD                                     0x170058
 #define DORQ_REG_IF_EN                                          0x170004
+#define DORQ_REG_MAX_RVFID_SIZE                                 0x1701ec
 #define DORQ_REG_MODE_ACT                                       0x170008
 /* [RW 5] The normal mode CID extraction offset. */
 #define DORQ_REG_NORM_CID_OFST                                  0x17002c
    writes the same initial credit to the rspa_crd_cnt and rspb_crd_cnt. The
    read reads this written value. */
 #define DORQ_REG_RSP_INIT_CRD                                   0x170048
+#define DORQ_REG_RSPB_CRD_CNT                                   0x1700b0
+#define DORQ_REG_VF_NORM_CID_BASE                               0x1701a0
+#define DORQ_REG_VF_NORM_CID_OFST                               0x1701f4
+#define DORQ_REG_VF_NORM_CID_WND_SIZE                           0x1701a4
+#define DORQ_REG_VF_NORM_MAX_CID_COUNT                          0x1701e4
+#define DORQ_REG_VF_NORM_VF_BASE                                0x1701a8
+/* [RW 10] VF type validation mask value */
+#define DORQ_REG_VF_TYPE_MASK_0                                         0x170218
+/* [RW 17] VF type validation Min MCID value */
+#define DORQ_REG_VF_TYPE_MAX_MCID_0                             0x1702d8
+/* [RW 17] VF type validation Max MCID value */
+#define DORQ_REG_VF_TYPE_MIN_MCID_0                             0x170298
+/* [RW 10] VF type validation comp value */
+#define DORQ_REG_VF_TYPE_VALUE_0                                0x170258
+#define DORQ_REG_VF_USAGE_CT_LIMIT                              0x170340
+
 /* [RW 4] Initial activity counter value on the load request; when the
    shortcut is done. */
 #define DORQ_REG_SHRT_ACT_CNT                                   0x170070
 #define HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0                       (0x1<<2)
 #define HC_CONFIG_0_REG_SINGLE_ISR_EN_0                                 (0x1<<1)
 #define HC_CONFIG_1_REG_BLOCK_DISABLE_1                                 (0x1<<0)
+#define DORQ_REG_VF_USAGE_CNT                                   0x170320
 #define HC_REG_AGG_INT_0                                        0x108050
 #define HC_REG_AGG_INT_1                                        0x108054
 #define HC_REG_ATTN_BIT                                         0x108120
 /* [R 32] Interrupt register #0 read */
 #define NIG_REG_NIG_INT_STS_0                                   0x103b0
 #define NIG_REG_NIG_INT_STS_1                                   0x103c0
+/* [RC 32] Interrupt register #0 read clear */
+#define NIG_REG_NIG_INT_STS_CLR_0                               0x103b4
 /* [R 32] Legacy E1 and E1H location for parity error mask register. */
 #define NIG_REG_NIG_PRTY_MASK                                   0x103dc
 /* [RW 32] Parity mask register #0 read/write */
    current task in process). */
 #define PBF_REG_DISABLE_NEW_TASK_PROC_P4                        0x14006c
 #define PBF_REG_DISABLE_PF                                      0x1402e8
+#define PBF_REG_DISABLE_VF                                      0x1402ec
 /* [RW 18] For port 0: For each client that is subject to WFQ (the
  * corresponding bit is 1); indicates to which of the credit registers this
  * client is mapped. For clients which are not credit blocked; their mapping
 #define PXP_REG_HST_DISCARD_INTERNAL_WRITES_STATUS              0x10309c
 /* [WB 160] Used for initialization of the inbound interrupts memory */
 #define PXP_REG_HST_INBOUND_INT                                 0x103800
+/* [RW 7] Indirect access to the permission table. The fields are : {Valid;
+ * VFID[5:0]}
+ */
+#define PXP_REG_HST_ZONE_PERMISSION_TABLE                       0x103400
 /* [RW 32] Interrupt mask register #0 read/write */
 #define PXP_REG_PXP_INT_MASK_0                                  0x103074
 #define PXP_REG_PXP_INT_MASK_1                                  0x103084
 #define HW_LOCK_RESOURCE_SPIO                                   2
 #define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT                   (0x1<<4)
 #define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR                   (0x1<<5)
+#define AEU_INPUTS_ATTN_BITS_BRB_HW_INTERRUPT                   (0x1<<19)
 #define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR                   (0x1<<18)
 #define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT                   (0x1<<31)
 #define AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR                   (0x1<<30)
 #define PCI_PM_DATA_B                                  0x414
 #define PCI_ID_VAL1                                    0x434
 #define PCI_ID_VAL2                                    0x438
+#define GRC_CONFIG_REG_PF_INIT_VF              0x624
+#define GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK 0xf
+/* First VF_NUM for PF is encoded in this register.
+ * The number of VFs assigned to a PF is assumed to be a multiple of 8.
+ * Software should program these bits based on Total Number of VFs \
+ * programmed for each PF.
+ * Since registers from 0x000-0x7ff are split across functions, each PF will
+ * have the same location for the same 4 bits
+ */
 
 #define PXPCS_TL_CONTROL_5                 0x814
 #define PXPCS_TL_CONTROL_5_UNKNOWNTYPE_ERR_ATTN    (1 << 29) /*WC*/
        (7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */
 
 
+#define PXP_VF_ADDR_IGU_START                          0
+#define PXP_VF_ADDR_IGU_SIZE                           0x3000
+#define PXP_VF_ADDR_IGU_END\
+       ((PXP_VF_ADDR_IGU_START) + (PXP_VF_ADDR_IGU_SIZE) - 1)
+
+#define PXP_VF_ADDR_USDM_QUEUES_START                  0x3000
+#define PXP_VF_ADDR_USDM_QUEUES_SIZE\
+       (PXP_VF_ADRR_NUM_QUEUES * PXP_ADDR_QUEUE_SIZE)
+#define PXP_VF_ADDR_USDM_QUEUES_END\
+       ((PXP_VF_ADDR_USDM_QUEUES_START) + (PXP_VF_ADDR_USDM_QUEUES_SIZE) - 1)
+
+#define PXP_VF_ADDR_CSDM_GLOBAL_START                  0x7600
+#define PXP_VF_ADDR_CSDM_GLOBAL_SIZE                   (PXP_ADDR_REG_SIZE)
+#define PXP_VF_ADDR_CSDM_GLOBAL_END\
+       ((PXP_VF_ADDR_CSDM_GLOBAL_START) + (PXP_VF_ADDR_CSDM_GLOBAL_SIZE) - 1)
+
+#define PXP_VF_ADDR_DB_START                           0x7c00
+#define PXP_VF_ADDR_DB_SIZE                            0x200
+#define PXP_VF_ADDR_DB_END\
+       ((PXP_VF_ADDR_DB_START) + (PXP_VF_ADDR_DB_SIZE) - 1)
+
 #define MDIO_REG_BANK_CL73_IEEEB0      0x0
 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL       0x0
 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN    0x0200
index 09b625e0fdaa999260daaca271adac8b67112108..7306416bc90d29af91461440ff19da77f07429e7 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_sp.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2011-2012 Broadcom Corporation
+ * Copyright (c) 2011-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -325,7 +325,7 @@ static inline int bnx2x_state_wait(struct bnx2x *bp, int state,
                        return 0;
                }
 
-               usleep_range(1000, 1000);
+               usleep_range(1000, 2000);
 
                if (bp->panic)
                        return -EIO;
@@ -707,7 +707,8 @@ static inline void bnx2x_vlan_mac_set_cmd_hdr_e2(struct bnx2x *bp,
 static inline void bnx2x_vlan_mac_set_rdata_hdr_e2(u32 cid, int type,
                                struct eth_classify_header *hdr, int rule_cnt)
 {
-       hdr->echo = (cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT);
+       hdr->echo = cpu_to_le32((cid & BNX2X_SWCID_MASK) |
+                               (type << BNX2X_SWCID_SHIFT));
        hdr->rule_cnt = (u8)rule_cnt;
 }
 
@@ -813,8 +814,9 @@ static inline void bnx2x_vlan_mac_set_rdata_hdr_e1x(struct bnx2x *bp,
 
        hdr->length = 1;
        hdr->offset = (u8)cam_offset;
-       hdr->client_id = 0xff;
-       hdr->echo = ((r->cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT));
+       hdr->client_id = cpu_to_le16(0xff);
+       hdr->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+                               (type << BNX2X_SWCID_SHIFT));
 }
 
 static inline void bnx2x_vlan_mac_set_cfg_entry_e1x(struct bnx2x *bp,
@@ -903,7 +905,7 @@ static void bnx2x_set_one_vlan_e2(struct bnx2x *bp,
                (struct eth_classify_rules_ramrod_data *)(raw->rdata);
        int rule_cnt = rule_idx + 1;
        union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
-       int cmd = elem->cmd_data.vlan_mac.cmd;
+       enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
        bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
        u16 vlan = elem->cmd_data.vlan_mac.u.vlan.vlan;
 
@@ -953,7 +955,7 @@ static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
                (struct eth_classify_rules_ramrod_data *)(raw->rdata);
        int rule_cnt = rule_idx + 1;
        union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
-       int cmd = elem->cmd_data.vlan_mac.cmd;
+       enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
        bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
        u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
        u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
@@ -1407,7 +1409,7 @@ static int bnx2x_wait_vlan_mac(struct bnx2x *bp,
 
                /* Wait until there are no pending commands */
                if (!bnx2x_exe_queue_empty(exeq))
-                       usleep_range(1000, 1000);
+                       usleep_range(1000, 2000);
                else
                        return 0;
        }
@@ -1442,7 +1444,7 @@ static int bnx2x_complete_vlan_mac(struct bnx2x *bp,
        if (cqe->message.error)
                return -EINVAL;
 
-       /* Run the next bulk of pending commands if requeted */
+       /* Run the next bulk of pending commands if requested */
        if (test_bit(RAMROD_CONT, ramrod_flags)) {
                rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
                if (rc < 0)
@@ -1532,7 +1534,7 @@ static inline int bnx2x_vlan_mac_get_registry_elem(
        bool restore,
        struct bnx2x_vlan_mac_registry_elem **re)
 {
-       int cmd = elem->cmd_data.vlan_mac.cmd;
+       enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
        struct bnx2x_vlan_mac_registry_elem *reg_elem;
 
        /* Allocate a new registry element if needed. */
@@ -1591,7 +1593,7 @@ static int bnx2x_execute_vlan_mac(struct bnx2x *bp,
        bool restore = test_bit(RAMROD_RESTORE, ramrod_flags);
        bool drv_only = test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags);
        struct bnx2x_vlan_mac_registry_elem *reg_elem;
-       int cmd;
+       enum bnx2x_vlan_mac_cmd cmd;
 
        /*
         * If DRIVER_ONLY execution is requested, cleanup a registry
@@ -2103,7 +2105,7 @@ static inline void __storm_memset_mac_filters(struct bnx2x *bp,
 static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp,
                                 struct bnx2x_rx_mode_ramrod_params *p)
 {
-       /* update the bp MAC filter structure  */
+       /* update the bp MAC filter structure */
        u32 mask = (1 << p->cl_id);
 
        struct tstorm_eth_mac_filter_config *mac_filters =
@@ -2166,7 +2168,7 @@ static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp,
                mac_filters->unmatched_unicast & ~mask;
 
        DP(BNX2X_MSG_SP, "drop_ucast 0x%x\ndrop_mcast 0x%x\n accp_ucast 0x%x\n"
-                                        "accp_mcast 0x%x\naccp_bcast 0x%x\n",
+                        "accp_mcast 0x%x\naccp_bcast 0x%x\n",
           mac_filters->ucast_drop_all, mac_filters->mcast_drop_all,
           mac_filters->ucast_accept_all, mac_filters->mcast_accept_all,
           mac_filters->bcast_accept_all);
@@ -2186,12 +2188,12 @@ static inline void bnx2x_rx_mode_set_rdata_hdr_e2(u32 cid,
                                struct eth_classify_header *hdr,
                                u8 rule_cnt)
 {
-       hdr->echo = cid;
+       hdr->echo = cpu_to_le32(cid);
        hdr->rule_cnt = rule_cnt;
 }
 
 static inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp,
-                               unsigned long accept_flags,
+                               unsigned long *accept_flags,
                                struct eth_filter_rules_cmd *cmd,
                                bool clear_accept_all)
 {
@@ -2201,33 +2203,33 @@ static inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp,
        state = ETH_FILTER_RULES_CMD_UCAST_DROP_ALL |
                ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
 
-       if (accept_flags) {
-               if (test_bit(BNX2X_ACCEPT_UNICAST, &accept_flags))
-                       state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+       if (test_bit(BNX2X_ACCEPT_UNICAST, accept_flags))
+               state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
 
-               if (test_bit(BNX2X_ACCEPT_MULTICAST, &accept_flags))
-                       state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
+       if (test_bit(BNX2X_ACCEPT_MULTICAST, accept_flags))
+               state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
 
-               if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept_flags)) {
-                       state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
-                       state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
-               }
+       if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, accept_flags)) {
+               state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+               state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
+       }
 
-               if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept_flags)) {
-                       state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
-                       state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
-               }
-               if (test_bit(BNX2X_ACCEPT_BROADCAST, &accept_flags))
-                       state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
+       if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, accept_flags)) {
+               state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
+               state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
+       }
 
-               if (test_bit(BNX2X_ACCEPT_UNMATCHED, &accept_flags)) {
-                       state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
-                       state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
-               }
-               if (test_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags))
-                       state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN;
+       if (test_bit(BNX2X_ACCEPT_BROADCAST, accept_flags))
+               state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
+
+       if (test_bit(BNX2X_ACCEPT_UNMATCHED, accept_flags)) {
+               state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+               state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
        }
 
+       if (test_bit(BNX2X_ACCEPT_ANY_VLAN, accept_flags))
+               state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN;
+
        /* Clear ACCEPT_ALL_XXX flags for FCoE L2 Queue */
        if (clear_accept_all) {
                state &= ~ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
@@ -2260,8 +2262,9 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
                data->rules[rule_idx].cmd_general_data =
                        ETH_FILTER_RULES_CMD_TX_CMD;
 
-               bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags,
-                       &(data->rules[rule_idx++]), false);
+               bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
+                                              &(data->rules[rule_idx++]),
+                                              false);
        }
 
        /* Rx */
@@ -2272,8 +2275,9 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
                data->rules[rule_idx].cmd_general_data =
                        ETH_FILTER_RULES_CMD_RX_CMD;
 
-               bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags,
-                       &(data->rules[rule_idx++]), false);
+               bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
+                                              &(data->rules[rule_idx++]),
+                                              false);
        }
 
 
@@ -2293,9 +2297,10 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
                        data->rules[rule_idx].cmd_general_data =
                                                ETH_FILTER_RULES_CMD_TX_CMD;
 
-                       bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags,
-                                                    &(data->rules[rule_idx++]),
+                       bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
+                                                      &(data->rules[rule_idx]),
                                                       true);
+                       rule_idx++;
                }
 
                /* Rx */
@@ -2306,9 +2311,10 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
                        data->rules[rule_idx].cmd_general_data =
                                                ETH_FILTER_RULES_CMD_RX_CMD;
 
-                       bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags,
-                                                    &(data->rules[rule_idx++]),
+                       bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
+                                                      &(data->rules[rule_idx]),
                                                       true);
+                       rule_idx++;
                }
        }
 
@@ -2429,7 +2435,7 @@ static int bnx2x_mcast_wait(struct bnx2x *bp,
 static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
                                   struct bnx2x_mcast_obj *o,
                                   struct bnx2x_mcast_ramrod_params *p,
-                                  int cmd)
+                                  enum bnx2x_mcast_cmd cmd)
 {
        int total_sz;
        struct bnx2x_pending_mcast_cmd *new_cmd;
@@ -2561,7 +2567,7 @@ static inline u8 bnx2x_mcast_get_rx_tx_flag(struct bnx2x_mcast_obj *o)
 static void bnx2x_mcast_set_one_rule_e2(struct bnx2x *bp,
                                        struct bnx2x_mcast_obj *o, int idx,
                                        union bnx2x_mcast_config_data *cfg_data,
-                                       int cmd)
+                                       enum bnx2x_mcast_cmd cmd)
 {
        struct bnx2x_raw_obj *r = &o->raw;
        struct eth_multicast_rules_ramrod_data *data =
@@ -2625,7 +2631,7 @@ static inline int bnx2x_mcast_handle_restore_cmd_e2(
        int *rdata_idx)
 {
        int cur_bin, cnt = *rdata_idx;
-       union bnx2x_mcast_config_data cfg_data = {0};
+       union bnx2x_mcast_config_data cfg_data = {NULL};
 
        /* go through the registry and configure the bins from it */
        for (cur_bin = bnx2x_mcast_get_next_bin(o, start_bin); cur_bin >= 0;
@@ -2657,7 +2663,7 @@ static inline void bnx2x_mcast_hdl_pending_add_e2(struct bnx2x *bp,
 {
        struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n;
        int cnt = *line_idx;
-       union bnx2x_mcast_config_data cfg_data = {0};
+       union bnx2x_mcast_config_data cfg_data = {NULL};
 
        list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head,
                                 link) {
@@ -2780,7 +2786,7 @@ static inline void bnx2x_mcast_hdl_add(struct bnx2x *bp,
        int *line_idx)
 {
        struct bnx2x_mcast_list_elem *mlist_pos;
-       union bnx2x_mcast_config_data cfg_data = {0};
+       union bnx2x_mcast_config_data cfg_data = {NULL};
        int cnt = *line_idx;
 
        list_for_each_entry(mlist_pos, &p->mcast_list, link) {
@@ -2790,7 +2796,7 @@ static inline void bnx2x_mcast_hdl_add(struct bnx2x *bp,
                cnt++;
 
                DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
-                                mlist_pos->mac);
+                  mlist_pos->mac);
        }
 
        *line_idx = cnt;
@@ -2827,7 +2833,8 @@ static inline void bnx2x_mcast_hdl_del(struct bnx2x *bp,
  * Returns number of lines filled in the ramrod data in total.
  */
 static inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp,
-                       struct bnx2x_mcast_ramrod_params *p, int cmd,
+                       struct bnx2x_mcast_ramrod_params *p,
+                       enum bnx2x_mcast_cmd cmd,
                        int start_cnt)
 {
        struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -2861,7 +2868,7 @@ static inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp,
 
 static int bnx2x_mcast_validate_e2(struct bnx2x *bp,
                                   struct bnx2x_mcast_ramrod_params *p,
-                                  int cmd)
+                                  enum bnx2x_mcast_cmd cmd)
 {
        struct bnx2x_mcast_obj *o = p->mcast_obj;
        int reg_sz = o->get_registry_size(o);
@@ -2930,8 +2937,9 @@ static inline void bnx2x_mcast_set_rdata_hdr_e2(struct bnx2x *bp,
        struct eth_multicast_rules_ramrod_data *data =
                (struct eth_multicast_rules_ramrod_data *)(r->rdata);
 
-       data->header.echo = ((r->cid & BNX2X_SWCID_MASK) |
-                         (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT));
+       data->header.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+                                       (BNX2X_FILTER_MCAST_PENDING <<
+                                        BNX2X_SWCID_SHIFT));
        data->header.rule_cnt = len;
 }
 
@@ -2965,7 +2973,7 @@ static inline int bnx2x_mcast_refresh_registry_e2(struct bnx2x *bp,
 
 static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
                                struct bnx2x_mcast_ramrod_params *p,
-                               int cmd)
+                               enum bnx2x_mcast_cmd cmd)
 {
        struct bnx2x_raw_obj *raw = &p->mcast_obj->raw;
        struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -3051,7 +3059,7 @@ static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
 
 static int bnx2x_mcast_validate_e1h(struct bnx2x *bp,
                                    struct bnx2x_mcast_ramrod_params *p,
-                                   int cmd)
+                                   enum bnx2x_mcast_cmd cmd)
 {
        /* Mark, that there is a work to do */
        if ((cmd == BNX2X_MCAST_CMD_DEL) || (cmd == BNX2X_MCAST_CMD_RESTORE))
@@ -3085,7 +3093,7 @@ static inline void bnx2x_mcast_hdl_add_e1h(struct bnx2x *bp,
                BNX2X_57711_SET_MC_FILTER(mc_filter, bit);
 
                DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC, bin %d\n",
-                                mlist_pos->mac, bit);
+                  mlist_pos->mac, bit);
 
                /* bookkeeping... */
                BIT_VEC64_SET_BIT(o->registry.aprox_match.vec,
@@ -3113,7 +3121,7 @@ static inline void bnx2x_mcast_hdl_restore_e1h(struct bnx2x *bp,
  */
 static int bnx2x_mcast_setup_e1h(struct bnx2x *bp,
                                 struct bnx2x_mcast_ramrod_params *p,
-                                int cmd)
+                                enum bnx2x_mcast_cmd cmd)
 {
        int i;
        struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -3167,7 +3175,7 @@ static int bnx2x_mcast_setup_e1h(struct bnx2x *bp,
 
 static int bnx2x_mcast_validate_e1(struct bnx2x *bp,
                                   struct bnx2x_mcast_ramrod_params *p,
-                                  int cmd)
+                                  enum bnx2x_mcast_cmd cmd)
 {
        struct bnx2x_mcast_obj *o = p->mcast_obj;
        int reg_sz = o->get_registry_size(o);
@@ -3240,7 +3248,7 @@ static void bnx2x_mcast_revert_e1(struct bnx2x *bp,
 static void bnx2x_mcast_set_one_rule_e1(struct bnx2x *bp,
                                        struct bnx2x_mcast_obj *o, int idx,
                                        union bnx2x_mcast_config_data *cfg_data,
-                                       int cmd)
+                                       enum bnx2x_mcast_cmd cmd)
 {
        struct bnx2x_raw_obj *r = &o->raw;
        struct mac_configuration_cmd *data =
@@ -3284,9 +3292,10 @@ static inline void bnx2x_mcast_set_rdata_hdr_e1(struct bnx2x *bp,
                     BNX2X_MAX_MULTICAST*(1 + r->func_id));
 
        data->hdr.offset = offset;
-       data->hdr.client_id = 0xff;
-       data->hdr.echo = ((r->cid & BNX2X_SWCID_MASK) |
-                         (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT));
+       data->hdr.client_id = cpu_to_le16(0xff);
+       data->hdr.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+                                    (BNX2X_FILTER_MCAST_PENDING <<
+                                     BNX2X_SWCID_SHIFT));
        data->hdr.length = len;
 }
 
@@ -3309,7 +3318,7 @@ static inline int bnx2x_mcast_handle_restore_cmd_e1(
 {
        struct bnx2x_mcast_mac_elem *elem;
        int i = 0;
-       union bnx2x_mcast_config_data cfg_data = {0};
+       union bnx2x_mcast_config_data cfg_data = {NULL};
 
        /* go through the registry and configure the MACs from it. */
        list_for_each_entry(elem, &o->registry.exact_match.macs, link) {
@@ -3319,7 +3328,7 @@ static inline int bnx2x_mcast_handle_restore_cmd_e1(
                i++;
 
                  DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
-                                  cfg_data.mac);
+                    cfg_data.mac);
        }
 
        *rdata_idx = i;
@@ -3334,7 +3343,7 @@ static inline int bnx2x_mcast_handle_pending_cmds_e1(
        struct bnx2x_pending_mcast_cmd *cmd_pos;
        struct bnx2x_mcast_mac_elem *pmac_pos;
        struct bnx2x_mcast_obj *o = p->mcast_obj;
-       union bnx2x_mcast_config_data cfg_data = {0};
+       union bnx2x_mcast_config_data cfg_data = {NULL};
        int cnt = 0;
 
 
@@ -3355,7 +3364,7 @@ static inline int bnx2x_mcast_handle_pending_cmds_e1(
                        cnt++;
 
                        DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
-                                        pmac_pos->mac);
+                          pmac_pos->mac);
                }
                break;
 
@@ -3458,7 +3467,7 @@ static inline int bnx2x_mcast_refresh_registry_e1(struct bnx2x *bp,
 
 static int bnx2x_mcast_setup_e1(struct bnx2x *bp,
                                struct bnx2x_mcast_ramrod_params *p,
-                               int cmd)
+                               enum bnx2x_mcast_cmd cmd)
 {
        struct bnx2x_mcast_obj *o = p->mcast_obj;
        struct bnx2x_raw_obj *raw = &o->raw;
@@ -3562,7 +3571,7 @@ static void bnx2x_mcast_set_registry_size_aprox(struct bnx2x_mcast_obj *o,
 
 int bnx2x_config_mcast(struct bnx2x *bp,
                       struct bnx2x_mcast_ramrod_params *p,
-                      int cmd)
+                      enum bnx2x_mcast_cmd cmd)
 {
        struct bnx2x_mcast_obj *o = p->mcast_obj;
        struct bnx2x_raw_obj *r = &o->raw;
@@ -4085,8 +4094,8 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
        DP(BNX2X_MSG_SP, "Configuring RSS\n");
 
        /* Set an echo field */
-       data->echo = (r->cid & BNX2X_SWCID_MASK) |
-                    (r->state << BNX2X_SWCID_SHIFT);
+       data->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+                                (r->state << BNX2X_SWCID_SHIFT));
 
        /* RSS mode */
        if (test_bit(BNX2X_RSS_MODE_DISABLED, &p->rss_flags))
@@ -4237,11 +4246,16 @@ int bnx2x_queue_state_change(struct bnx2x *bp,
        unsigned long *pending = &o->pending;
 
        /* Check that the requested transition is legal */
-       if (o->check_transition(bp, o, params))
+       rc = o->check_transition(bp, o, params);
+       if (rc) {
+               BNX2X_ERR("check transition returned an error. rc %d\n", rc);
                return -EINVAL;
+       }
 
        /* Set "pending" bit */
+       DP(BNX2X_MSG_SP, "pending bit was=%lx\n", o->pending);
        pending_bit = o->set_pending(o, params);
+       DP(BNX2X_MSG_SP, "pending bit now=%lx\n", o->pending);
 
        /* Don't send a command if only driver cleanup was requested */
        if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags))
@@ -5025,8 +5039,11 @@ static int bnx2x_queue_chk_transition(struct bnx2x *bp,
         * Don't allow a next state transition if we are in the middle of
         * the previous one.
         */
-       if (o->pending)
+       if (o->pending) {
+               BNX2X_ERR("Blocking transition since pending was %lx\n",
+                         o->pending);
                return -EBUSY;
+       }
 
        switch (state) {
        case BNX2X_Q_STATE_RESET:
@@ -5199,6 +5216,27 @@ void bnx2x_init_queue_obj(struct bnx2x *bp,
        obj->set_pending = bnx2x_queue_set_pending;
 }
 
+/* return a queue object's logical state*/
+int bnx2x_get_q_logical_state(struct bnx2x *bp,
+                              struct bnx2x_queue_sp_obj *obj)
+{
+       switch (obj->state) {
+       case BNX2X_Q_STATE_ACTIVE:
+       case BNX2X_Q_STATE_MULTI_COS:
+               return BNX2X_Q_LOGICAL_STATE_ACTIVE;
+       case BNX2X_Q_STATE_RESET:
+       case BNX2X_Q_STATE_INITIALIZED:
+       case BNX2X_Q_STATE_MCOS_TERMINATED:
+       case BNX2X_Q_STATE_INACTIVE:
+       case BNX2X_Q_STATE_STOPPED:
+       case BNX2X_Q_STATE_TERMINATED:
+       case BNX2X_Q_STATE_FLRED:
+               return BNX2X_Q_LOGICAL_STATE_STOPPED;
+       default:
+               return -EINVAL;
+       }
+}
+
 /********************** Function state object *********************************/
 enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
                                           struct bnx2x_func_sp_obj *o)
@@ -5631,9 +5669,9 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
        memset(rdata, 0, sizeof(*rdata));
 
        /* Fill the ramrod data with provided parameters */
-       rdata->function_mode = (u8)start_params->mf_mode;
-       rdata->sd_vlan_tag   = cpu_to_le16(start_params->sd_vlan_tag);
-       rdata->path_id       = BP_PATH(bp);
+       rdata->function_mode    = (u8)start_params->mf_mode;
+       rdata->sd_vlan_tag      = cpu_to_le16(start_params->sd_vlan_tag);
+       rdata->path_id          = BP_PATH(bp);
        rdata->network_cos_mode = start_params->network_cos_mode;
 
        /*
@@ -5716,21 +5754,20 @@ inline int bnx2x_func_send_afex_viflists(struct bnx2x *bp,
        struct bnx2x_func_sp_obj *o = params->f_obj;
        struct afex_vif_list_ramrod_data *rdata =
                (struct afex_vif_list_ramrod_data *)o->afex_rdata;
-       struct bnx2x_func_afex_viflists_params *afex_viflist_params =
+       struct bnx2x_func_afex_viflists_params *afex_vif_params =
                &params->params.afex_viflists;
        u64 *p_rdata = (u64 *)rdata;
 
        memset(rdata, 0, sizeof(*rdata));
 
        /* Fill the ramrod data with provided parameters */
-       rdata->vif_list_index = afex_viflist_params->vif_list_index;
-       rdata->func_bit_map = afex_viflist_params->func_bit_map;
-       rdata->afex_vif_list_command =
-               afex_viflist_params->afex_vif_list_command;
-       rdata->func_to_clear = afex_viflist_params->func_to_clear;
+       rdata->vif_list_index = cpu_to_le16(afex_vif_params->vif_list_index);
+       rdata->func_bit_map          = afex_vif_params->func_bit_map;
+       rdata->afex_vif_list_command = afex_vif_params->afex_vif_list_command;
+       rdata->func_to_clear         = afex_vif_params->func_to_clear;
 
        /* send in echo type of sub command */
-       rdata->echo = afex_viflist_params->afex_vif_list_command;
+       rdata->echo = afex_vif_params->afex_vif_list_command;
 
        /*  No need for an explicit memory barrier here as long we would
         *  need to ensure the ordering of writing to the SPQ element
index adbd91b1bdfc56a6edc93c3409f798e27de1d84c..ff907609b9fc5cef7c975b2a28453d562e09fc02 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_sp.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2011-2012 Broadcom Corporation
+ * Copyright (c) 2011-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -54,7 +54,7 @@ typedef enum {
        BNX2X_OBJ_TYPE_RX_TX,
 } bnx2x_obj_type;
 
-/* Filtering states */
+/* Public slow path states */
 enum {
        BNX2X_FILTER_MAC_PENDING,
        BNX2X_FILTER_VLAN_PENDING,
@@ -524,7 +524,7 @@ struct bnx2x_mcast_ramrod_params {
        int mcast_list_len;
 };
 
-enum {
+enum bnx2x_mcast_cmd {
        BNX2X_MCAST_CMD_ADD,
        BNX2X_MCAST_CMD_CONT,
        BNX2X_MCAST_CMD_DEL,
@@ -573,7 +573,8 @@ struct bnx2x_mcast_obj {
         * @param cmd command to execute (BNX2X_MCAST_CMD_X, see above)
         */
        int (*config_mcast)(struct bnx2x *bp,
-                               struct bnx2x_mcast_ramrod_params *p, int cmd);
+                           struct bnx2x_mcast_ramrod_params *p,
+                           enum bnx2x_mcast_cmd cmd);
 
        /**
         * Fills the ramrod data during the RESTORE flow.
@@ -590,11 +591,13 @@ struct bnx2x_mcast_obj {
                           int start_bin, int *rdata_idx);
 
        int (*enqueue_cmd)(struct bnx2x *bp, struct bnx2x_mcast_obj *o,
-                          struct bnx2x_mcast_ramrod_params *p, int cmd);
+                          struct bnx2x_mcast_ramrod_params *p,
+                          enum bnx2x_mcast_cmd cmd);
 
        void (*set_one_rule)(struct bnx2x *bp,
                             struct bnx2x_mcast_obj *o, int idx,
-                            union bnx2x_mcast_config_data *cfg_data, int cmd);
+                            union bnx2x_mcast_config_data *cfg_data,
+                            enum bnx2x_mcast_cmd cmd);
 
        /** Checks if there are more mcast MACs to be set or a previous
         *  command is still pending.
@@ -617,7 +620,8 @@ struct bnx2x_mcast_obj {
         * feasible.
         */
        int (*validate)(struct bnx2x *bp,
-                       struct bnx2x_mcast_ramrod_params *p, int cmd);
+                       struct bnx2x_mcast_ramrod_params *p,
+                       enum bnx2x_mcast_cmd cmd);
 
        /**
         * Restore the values of internal counters in case of a failure.
@@ -776,6 +780,12 @@ enum bnx2x_q_state {
        BNX2X_Q_STATE_MAX,
 };
 
+/* Allowed Queue states */
+enum bnx2x_q_logical_state {
+       BNX2X_Q_LOGICAL_STATE_ACTIVE,
+       BNX2X_Q_LOGICAL_STATE_STOPPED,
+};
+
 /* Allowed commands */
 enum bnx2x_queue_cmd {
        BNX2X_Q_CMD_INIT,
@@ -1261,6 +1271,9 @@ void bnx2x_init_queue_obj(struct bnx2x *bp,
 int bnx2x_queue_state_change(struct bnx2x *bp,
                             struct bnx2x_queue_state_params *params);
 
+int bnx2x_get_q_logical_state(struct bnx2x *bp,
+                              struct bnx2x_queue_sp_obj *obj);
+
 /********************* VLAN-MAC ****************/
 void bnx2x_init_mac_obj(struct bnx2x *bp,
                        struct bnx2x_vlan_mac_obj *mac_obj,
@@ -1338,7 +1351,8 @@ void bnx2x_init_mcast_obj(struct bnx2x *bp,
  *         completions.
  */
 int bnx2x_config_mcast(struct bnx2x *bp,
-                      struct bnx2x_mcast_ramrod_params *p, int cmd);
+                      struct bnx2x_mcast_ramrod_params *p,
+                      enum bnx2x_mcast_cmd cmd);
 
 /****************** CREDIT POOL ****************/
 void bnx2x_init_mac_credit_pool(struct bnx2x *bp,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
new file mode 100644 (file)
index 0000000..6adfa20
--- /dev/null
@@ -0,0 +1,3198 @@
+/* bnx2x_sriov.c: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ *            Ariel Elior <ariele@broadcom.com>
+ *
+ */
+#include "bnx2x.h"
+#include "bnx2x_init.h"
+#include "bnx2x_cmn.h"
+#include <linux/crc32.h>
+
+/* General service functions */
+static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
+                                        u16 pf_id)
+{
+       REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
+               pf_id);
+       REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
+               pf_id);
+       REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
+               pf_id);
+       REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
+               pf_id);
+}
+
+static void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
+                                       u8 enable)
+{
+       REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
+               enable);
+       REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
+               enable);
+       REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
+               enable);
+       REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
+               enable);
+}
+
+int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
+{
+       int idx;
+
+       for_each_vf(bp, idx)
+               if (bnx2x_vf(bp, idx, abs_vfid) == abs_vfid)
+                       break;
+       return idx;
+}
+
+static
+struct bnx2x_virtf *bnx2x_vf_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
+{
+       u16 idx =  (u16)bnx2x_vf_idx_by_abs_fid(bp, abs_vfid);
+       return (idx < BNX2X_NR_VIRTFN(bp)) ? BP_VF(bp, idx) : NULL;
+}
+
+static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                               u8 igu_sb_id, u8 segment, u16 index, u8 op,
+                               u8 update)
+{
+       /* acking a VF sb through the PF - use the GRC */
+       u32 ctl;
+       u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
+       u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
+       u32 func_encode = vf->abs_vfid;
+       u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + igu_sb_id;
+       struct igu_regular cmd_data = {0};
+
+       cmd_data.sb_id_and_flags =
+                       ((index << IGU_REGULAR_SB_INDEX_SHIFT) |
+                        (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) |
+                        (update << IGU_REGULAR_BUPDATE_SHIFT) |
+                        (op << IGU_REGULAR_ENABLE_INT_SHIFT));
+
+       ctl = addr_encode << IGU_CTRL_REG_ADDRESS_SHIFT         |
+             func_encode << IGU_CTRL_REG_FID_SHIFT             |
+             IGU_CTRL_CMD_TYPE_WR << IGU_CTRL_REG_TYPE_SHIFT;
+
+       DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+          cmd_data.sb_id_and_flags, igu_addr_data);
+       REG_WR(bp, igu_addr_data, cmd_data.sb_id_and_flags);
+       mmiowb();
+       barrier();
+
+       DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+          ctl, igu_addr_ctl);
+       REG_WR(bp, igu_addr_ctl, ctl);
+       mmiowb();
+       barrier();
+}
+/* VFOP - VF slow-path operation support */
+
+#define BNX2X_VFOP_FILTER_ADD_CNT_MAX          0x10000
+
+/* VFOP operations states */
+enum bnx2x_vfop_qctor_state {
+          BNX2X_VFOP_QCTOR_INIT,
+          BNX2X_VFOP_QCTOR_SETUP,
+          BNX2X_VFOP_QCTOR_INT_EN
+};
+
+enum bnx2x_vfop_qdtor_state {
+          BNX2X_VFOP_QDTOR_HALT,
+          BNX2X_VFOP_QDTOR_TERMINATE,
+          BNX2X_VFOP_QDTOR_CFCDEL,
+          BNX2X_VFOP_QDTOR_DONE
+};
+
+enum bnx2x_vfop_vlan_mac_state {
+          BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
+          BNX2X_VFOP_VLAN_MAC_CLEAR,
+          BNX2X_VFOP_VLAN_MAC_CHK_DONE,
+          BNX2X_VFOP_MAC_CONFIG_LIST,
+          BNX2X_VFOP_VLAN_CONFIG_LIST,
+          BNX2X_VFOP_VLAN_CONFIG_LIST_0
+};
+
+enum bnx2x_vfop_qsetup_state {
+          BNX2X_VFOP_QSETUP_CTOR,
+          BNX2X_VFOP_QSETUP_VLAN0,
+          BNX2X_VFOP_QSETUP_DONE
+};
+
+enum bnx2x_vfop_mcast_state {
+          BNX2X_VFOP_MCAST_DEL,
+          BNX2X_VFOP_MCAST_ADD,
+          BNX2X_VFOP_MCAST_CHK_DONE
+};
+enum bnx2x_vfop_qflr_state {
+          BNX2X_VFOP_QFLR_CLR_VLAN,
+          BNX2X_VFOP_QFLR_CLR_MAC,
+          BNX2X_VFOP_QFLR_TERMINATE,
+          BNX2X_VFOP_QFLR_DONE
+};
+
+enum bnx2x_vfop_flr_state {
+          BNX2X_VFOP_FLR_QUEUES,
+          BNX2X_VFOP_FLR_HW
+};
+
+enum bnx2x_vfop_close_state {
+          BNX2X_VFOP_CLOSE_QUEUES,
+          BNX2X_VFOP_CLOSE_HW
+};
+
+enum bnx2x_vfop_rxmode_state {
+          BNX2X_VFOP_RXMODE_CONFIG,
+          BNX2X_VFOP_RXMODE_DONE
+};
+
+enum bnx2x_vfop_qteardown_state {
+          BNX2X_VFOP_QTEARDOWN_RXMODE,
+          BNX2X_VFOP_QTEARDOWN_CLR_VLAN,
+          BNX2X_VFOP_QTEARDOWN_CLR_MAC,
+          BNX2X_VFOP_QTEARDOWN_QDTOR,
+          BNX2X_VFOP_QTEARDOWN_DONE
+};
+
+#define bnx2x_vfop_reset_wq(vf)        atomic_set(&vf->op_in_progress, 0)
+
+void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                             struct bnx2x_queue_init_params *init_params,
+                             struct bnx2x_queue_setup_params *setup_params,
+                             u16 q_idx, u16 sb_idx)
+{
+       DP(BNX2X_MSG_IOV,
+          "VF[%d] Q_SETUP: txq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, flags=0x%lx, traffic-type=%d",
+          vf->abs_vfid,
+          q_idx,
+          sb_idx,
+          init_params->tx.sb_cq_index,
+          init_params->tx.hc_rate,
+          setup_params->flags,
+          setup_params->txq_params.traffic_type);
+}
+
+void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                           struct bnx2x_queue_init_params *init_params,
+                           struct bnx2x_queue_setup_params *setup_params,
+                           u16 q_idx, u16 sb_idx)
+{
+       struct bnx2x_rxq_setup_params *rxq_params = &setup_params->rxq_params;
+
+       DP(BNX2X_MSG_IOV, "VF[%d] Q_SETUP: rxq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, mtu=%d, buf-size=%d\n"
+          "sge-size=%d, max_sge_pkt=%d, tpa-agg-size=%d, flags=0x%lx, drop-flags=0x%x, cache-log=%d\n",
+          vf->abs_vfid,
+          q_idx,
+          sb_idx,
+          init_params->rx.sb_cq_index,
+          init_params->rx.hc_rate,
+          setup_params->gen_params.mtu,
+          rxq_params->buf_sz,
+          rxq_params->sge_buf_sz,
+          rxq_params->max_sges_pkt,
+          rxq_params->tpa_agg_sz,
+          setup_params->flags,
+          rxq_params->drop_flags,
+          rxq_params->cache_line_log);
+}
+
+void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
+                          struct bnx2x_virtf *vf,
+                          struct bnx2x_vf_queue *q,
+                          struct bnx2x_vfop_qctor_params *p,
+                          unsigned long q_type)
+{
+       struct bnx2x_queue_init_params *init_p = &p->qstate.params.init;
+       struct bnx2x_queue_setup_params *setup_p = &p->prep_qsetup;
+
+       /* INIT */
+
+       /* Enable host coalescing in the transition to INIT state */
+       if (test_bit(BNX2X_Q_FLG_HC, &init_p->rx.flags))
+               __set_bit(BNX2X_Q_FLG_HC_EN, &init_p->rx.flags);
+
+       if (test_bit(BNX2X_Q_FLG_HC, &init_p->tx.flags))
+               __set_bit(BNX2X_Q_FLG_HC_EN, &init_p->tx.flags);
+
+       /* FW SB ID */
+       init_p->rx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+       init_p->tx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+
+       /* context */
+       init_p->cxts[0] = q->cxt;
+
+       /* SETUP */
+
+       /* Setup-op general parameters */
+       setup_p->gen_params.spcl_id = vf->sp_cl_id;
+       setup_p->gen_params.stat_id = vfq_stat_id(vf, q);
+
+       /* Setup-op pause params:
+        * Nothing to do, the pause thresholds are set by default to 0 which
+        * effectively turns off the feature for this queue. We don't want
+        * one queue (VF) to interfering with another queue (another VF)
+        */
+       if (vf->cfg_flags & VF_CFG_FW_FC)
+               BNX2X_ERR("No support for pause to VFs (abs_vfid: %d)\n",
+                         vf->abs_vfid);
+       /* Setup-op flags:
+        * collect statistics, zero statistics, local-switching, security,
+        * OV for Flex10, RSS and MCAST for leading
+        */
+       if (test_bit(BNX2X_Q_FLG_STATS, &setup_p->flags))
+               __set_bit(BNX2X_Q_FLG_ZERO_STATS, &setup_p->flags);
+
+       /* for VFs, enable tx switching, bd coherency, and mac address
+        * anti-spoofing
+        */
+       __set_bit(BNX2X_Q_FLG_TX_SWITCH, &setup_p->flags);
+       __set_bit(BNX2X_Q_FLG_TX_SEC, &setup_p->flags);
+       __set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
+
+       if (vfq_is_leading(q)) {
+               __set_bit(BNX2X_Q_FLG_LEADING_RSS, &setup_p->flags);
+               __set_bit(BNX2X_Q_FLG_MCAST, &setup_p->flags);
+       }
+
+       /* Setup-op rx parameters */
+       if (test_bit(BNX2X_Q_TYPE_HAS_RX, &q_type)) {
+               struct bnx2x_rxq_setup_params *rxq_p = &setup_p->rxq_params;
+
+               rxq_p->cl_qzone_id = vfq_qzone_id(vf, q);
+               rxq_p->fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+               rxq_p->rss_engine_id = FW_VF_HANDLE(vf->abs_vfid);
+
+               if (test_bit(BNX2X_Q_FLG_TPA, &setup_p->flags))
+                       rxq_p->max_tpa_queues = BNX2X_VF_MAX_TPA_AGG_QUEUES;
+       }
+
+       /* Setup-op tx parameters */
+       if (test_bit(BNX2X_Q_TYPE_HAS_TX, &q_type)) {
+               setup_p->txq_params.tss_leading_cl_id = vf->leading_rss;
+               setup_p->txq_params.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+       }
+}
+
+/* VFOP queue construction */
+static void bnx2x_vfop_qctor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vfop_args_qctor *args = &vfop->args.qctor;
+       struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
+       enum bnx2x_vfop_qctor_state state = vfop->state;
+
+       bnx2x_vfop_reset_wq(vf);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_QCTOR_INIT:
+
+               /* has this queue already been opened? */
+               if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+                   BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+                       DP(BNX2X_MSG_IOV,
+                          "Entered qctor but queue was already up. Aborting gracefully\n");
+                       goto op_done;
+               }
+
+               /* next state */
+               vfop->state = BNX2X_VFOP_QCTOR_SETUP;
+
+               q_params->cmd = BNX2X_Q_CMD_INIT;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_QCTOR_SETUP:
+               /* next state */
+               vfop->state = BNX2X_VFOP_QCTOR_INT_EN;
+
+               /* copy pre-prepared setup params to the queue-state params */
+               vfop->op_p->qctor.qstate.params.setup =
+                       vfop->op_p->qctor.prep_qsetup;
+
+               q_params->cmd = BNX2X_Q_CMD_SETUP;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_QCTOR_INT_EN:
+
+               /* enable interrupts */
+               bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, args->sb_idx),
+                                   USTORM_ID, 0, IGU_INT_ENABLE, 0);
+               goto op_done;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_err:
+       BNX2X_ERR("QCTOR[%d:%d] error: cmd %d, rc %d\n",
+                 vf->abs_vfid, args->qid, q_params->cmd, vfop->rc);
+op_done:
+       bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+       return;
+}
+
+static int bnx2x_vfop_qctor_cmd(struct bnx2x *bp,
+                               struct bnx2x_virtf *vf,
+                               struct bnx2x_vfop_cmd *cmd,
+                               int qid)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               vf->op_params.qctor.qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+
+               vfop->args.qctor.qid = qid;
+               vfop->args.qctor.sb_idx = bnx2x_vfq(vf, qid, sb_idx);
+
+               bnx2x_vfop_opset(BNX2X_VFOP_QCTOR_INIT,
+                                bnx2x_vfop_qctor, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qctor,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+/* VFOP queue destruction */
+static void bnx2x_vfop_qdtor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vfop_args_qdtor *qdtor = &vfop->args.qdtor;
+       struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
+       enum bnx2x_vfop_qdtor_state state = vfop->state;
+
+       bnx2x_vfop_reset_wq(vf);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_QDTOR_HALT:
+
+               /* has this queue already been stopped? */
+               if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+                   BNX2X_Q_LOGICAL_STATE_STOPPED) {
+                       DP(BNX2X_MSG_IOV,
+                          "Entered qdtor but queue was already stopped. Aborting gracefully\n");
+                       goto op_done;
+               }
+
+               /* next state */
+               vfop->state = BNX2X_VFOP_QDTOR_TERMINATE;
+
+               q_params->cmd = BNX2X_Q_CMD_HALT;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_QDTOR_TERMINATE:
+               /* next state */
+               vfop->state = BNX2X_VFOP_QDTOR_CFCDEL;
+
+               q_params->cmd = BNX2X_Q_CMD_TERMINATE;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_QDTOR_CFCDEL:
+               /* next state */
+               vfop->state = BNX2X_VFOP_QDTOR_DONE;
+
+               q_params->cmd = BNX2X_Q_CMD_CFC_DEL;
+               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+       BNX2X_ERR("QDTOR[%d:%d] error: cmd %d, rc %d\n",
+                 vf->abs_vfid, qdtor->qid, q_params->cmd, vfop->rc);
+op_done:
+       case BNX2X_VFOP_QDTOR_DONE:
+               /* invalidate the context */
+               qdtor->cxt->ustorm_ag_context.cdu_usage = 0;
+               qdtor->cxt->xstorm_ag_context.cdu_reserved = 0;
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_pending:
+       return;
+}
+
+static int bnx2x_vfop_qdtor_cmd(struct bnx2x *bp,
+                               struct bnx2x_virtf *vf,
+                               struct bnx2x_vfop_cmd *cmd,
+                               int qid)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_queue_state_params *qstate =
+                       &vf->op_params.qctor.qstate;
+
+               memset(qstate, 0, sizeof(*qstate));
+               qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+
+               vfop->args.qdtor.qid = qid;
+               vfop->args.qdtor.cxt = bnx2x_vfq(vf, qid, cxt);
+
+               bnx2x_vfop_opset(BNX2X_VFOP_QDTOR_HALT,
+                                bnx2x_vfop_qdtor, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdtor,
+                                            cmd->block);
+       }
+       DP(BNX2X_MSG_IOV, "VF[%d] failed to add a vfop.\n", vf->abs_vfid);
+       return -ENOMEM;
+}
+
+static void
+bnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
+{
+       struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+       if (vf) {
+               if (!vf_sb_count(vf))
+                       vf->igu_base_id = igu_sb_id;
+               ++vf_sb_count(vf);
+       }
+}
+
+/* VFOP MAC/VLAN helpers */
+static inline void bnx2x_vfop_credit(struct bnx2x *bp,
+                                    struct bnx2x_vfop *vfop,
+                                    struct bnx2x_vlan_mac_obj *obj)
+{
+       struct bnx2x_vfop_args_filters *args = &vfop->args.filters;
+
+       /* update credit only if there is no error
+        * and a valid credit counter
+        */
+       if (!vfop->rc && args->credit) {
+               int cnt = 0;
+               struct list_head *pos;
+
+               list_for_each(pos, &obj->head)
+                       cnt++;
+
+               atomic_set(args->credit, cnt);
+       }
+}
+
+static int bnx2x_vfop_set_user_req(struct bnx2x *bp,
+                                   struct bnx2x_vfop_filter *pos,
+                                   struct bnx2x_vlan_mac_data *user_req)
+{
+       user_req->cmd = pos->add ? BNX2X_VLAN_MAC_ADD :
+               BNX2X_VLAN_MAC_DEL;
+
+       switch (pos->type) {
+       case BNX2X_VFOP_FILTER_MAC:
+               memcpy(user_req->u.mac.mac, pos->mac, ETH_ALEN);
+               break;
+       case BNX2X_VFOP_FILTER_VLAN:
+               user_req->u.vlan.vlan = pos->vid;
+               break;
+       default:
+               BNX2X_ERR("Invalid filter type, skipping\n");
+               return 1;
+       }
+       return 0;
+}
+
+static int
+bnx2x_vfop_config_vlan0(struct bnx2x *bp,
+                       struct bnx2x_vlan_mac_ramrod_params *vlan_mac,
+                       bool add)
+{
+       int rc;
+
+       vlan_mac->user_req.cmd = add ? BNX2X_VLAN_MAC_ADD :
+               BNX2X_VLAN_MAC_DEL;
+       vlan_mac->user_req.u.vlan.vlan = 0;
+
+       rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+       if (rc == -EEXIST)
+               rc = 0;
+       return rc;
+}
+
+static int bnx2x_vfop_config_list(struct bnx2x *bp,
+                                 struct bnx2x_vfop_filters *filters,
+                                 struct bnx2x_vlan_mac_ramrod_params *vlan_mac)
+{
+       struct bnx2x_vfop_filter *pos, *tmp;
+       struct list_head rollback_list, *filters_list = &filters->head;
+       struct bnx2x_vlan_mac_data *user_req = &vlan_mac->user_req;
+       int rc = 0, cnt = 0;
+
+       INIT_LIST_HEAD(&rollback_list);
+
+       list_for_each_entry_safe(pos, tmp, filters_list, link) {
+               if (bnx2x_vfop_set_user_req(bp, pos, user_req))
+                       continue;
+
+               rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+               if (rc >= 0) {
+                       cnt += pos->add ? 1 : -1;
+                       list_del(&pos->link);
+                       list_add(&pos->link, &rollback_list);
+                       rc = 0;
+               } else if (rc == -EEXIST) {
+                       rc = 0;
+               } else {
+                       BNX2X_ERR("Failed to add a new vlan_mac command\n");
+                       break;
+               }
+       }
+
+       /* rollback if error or too many rules added */
+       if (rc || cnt > filters->add_cnt) {
+               BNX2X_ERR("error or too many rules added. Performing rollback\n");
+               list_for_each_entry_safe(pos, tmp, &rollback_list, link) {
+                       pos->add = !pos->add;   /* reverse op */
+                       bnx2x_vfop_set_user_req(bp, pos, user_req);
+                       bnx2x_config_vlan_mac(bp, vlan_mac);
+                       list_del(&pos->link);
+               }
+               cnt = 0;
+               if (!rc)
+                       rc = -EINVAL;
+       }
+       filters->add_cnt = cnt;
+       return rc;
+}
+
+/* VFOP set VLAN/MAC */
+static void bnx2x_vfop_vlan_mac(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vlan_mac_ramrod_params *vlan_mac = &vfop->op_p->vlan_mac;
+       struct bnx2x_vlan_mac_obj *obj = vlan_mac->vlan_mac_obj;
+       struct bnx2x_vfop_filters *filters = vfop->args.filters.multi_filter;
+
+       enum bnx2x_vfop_vlan_mac_state state = vfop->state;
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       bnx2x_vfop_reset_wq(vf);
+
+       switch (state) {
+       case BNX2X_VFOP_VLAN_MAC_CLEAR:
+               /* next state */
+               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+               /* do delete */
+               vfop->rc = obj->delete_all(bp, obj,
+                                          &vlan_mac->user_req.vlan_mac_flags,
+                                          &vlan_mac->ramrod_flags);
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+       case BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE:
+               /* next state */
+               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+               /* do config */
+               vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+               if (vfop->rc == -EEXIST)
+                       vfop->rc = 0;
+
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+       case BNX2X_VFOP_VLAN_MAC_CHK_DONE:
+               vfop->rc = !!obj->raw.check_pending(&obj->raw);
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+       case BNX2X_VFOP_MAC_CONFIG_LIST:
+               /* next state */
+               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+               /* do list config */
+               vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
+               if (vfop->rc)
+                       goto op_err;
+
+               set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
+               vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+       case BNX2X_VFOP_VLAN_CONFIG_LIST:
+               /* next state */
+               vfop->state = BNX2X_VFOP_VLAN_CONFIG_LIST_0;
+
+               /* remove vlan0 - could be no-op */
+               vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, false);
+               if (vfop->rc)
+                       goto op_err;
+
+               /* Do vlan list config. if this operation fails we try to
+                * restore vlan0 to keep the queue is working order
+                */
+               vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
+               if (!vfop->rc) {
+                       set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
+                       vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+               }
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); /* fall-through */
+
+       case BNX2X_VFOP_VLAN_CONFIG_LIST_0:
+               /* next state */
+               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+               if (list_empty(&obj->head))
+                       /* add vlan0 */
+                       vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, true);
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_err:
+       BNX2X_ERR("VLAN-MAC error: rc %d\n", vfop->rc);
+op_done:
+       kfree(filters);
+       bnx2x_vfop_credit(bp, vfop, obj);
+       bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+       return;
+}
+
+struct bnx2x_vfop_vlan_mac_flags {
+       bool drv_only;
+       bool dont_consume;
+       bool single_cmd;
+       bool add;
+};
+
+static void
+bnx2x_vfop_vlan_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
+                               struct bnx2x_vfop_vlan_mac_flags *flags)
+{
+       struct bnx2x_vlan_mac_data *ureq = &ramrod->user_req;
+
+       memset(ramrod, 0, sizeof(*ramrod));
+
+       /* ramrod flags */
+       if (flags->drv_only)
+               set_bit(RAMROD_DRV_CLR_ONLY, &ramrod->ramrod_flags);
+       if (flags->single_cmd)
+               set_bit(RAMROD_EXEC, &ramrod->ramrod_flags);
+
+       /* mac_vlan flags */
+       if (flags->dont_consume)
+               set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, &ureq->vlan_mac_flags);
+
+       /* cmd */
+       ureq->cmd = flags->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL;
+}
+
+static inline void
+bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
+                          struct bnx2x_vfop_vlan_mac_flags *flags)
+{
+       bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, flags);
+       set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
+}
+
+static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp,
+                                    struct bnx2x_virtf *vf,
+                                    struct bnx2x_vfop_cmd *cmd,
+                                    int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = NULL,   /* single */
+                       .credit = NULL,         /* consume credit */
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = drv_only,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = true,
+                       .add = false /* don't care */,
+               };
+               struct bnx2x_vlan_mac_ramrod_params *ramrod =
+                       &vf->op_params.vlan_mac;
+
+               /* set ramrod params */
+               bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
+
+               /* set object */
+               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+
+               /* set extra args */
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+                           struct bnx2x_virtf *vf,
+                           struct bnx2x_vfop_cmd *cmd,
+                           struct bnx2x_vfop_filters *macs,
+                           int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = macs,
+                       .credit = NULL,         /* consume credit */
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = drv_only,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = false,
+                       .add = false, /* don't care since only the items in the
+                                      * filters list affect the sp operation,
+                                      * not the list itself
+                                      */
+               };
+               struct bnx2x_vlan_mac_ramrod_params *ramrod =
+                       &vf->op_params.vlan_mac;
+
+               /* set ramrod params */
+               bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
+
+               /* set object */
+               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+
+               /* set extra args */
+               filters.multi_filter->add_cnt = BNX2X_VFOP_FILTER_ADD_CNT_MAX;
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_MAC_CONFIG_LIST,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+                           struct bnx2x_virtf *vf,
+                           struct bnx2x_vfop_cmd *cmd,
+                           int qid, u16 vid, bool add)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = NULL, /* single command */
+                       .credit = &bnx2x_vfq(vf, qid, vlan_count),
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = false,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = true,
+                       .add = add,
+               };
+               struct bnx2x_vlan_mac_ramrod_params *ramrod =
+                       &vf->op_params.vlan_mac;
+
+               /* set ramrod params */
+               bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+               ramrod->user_req.u.vlan.vlan = vid;
+
+               /* set object */
+               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+               /* set extra args */
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp,
+                              struct bnx2x_virtf *vf,
+                              struct bnx2x_vfop_cmd *cmd,
+                              int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = NULL, /* single command */
+                       .credit = &bnx2x_vfq(vf, qid, vlan_count),
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = drv_only,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = true,
+                       .add = false, /* don't care */
+               };
+               struct bnx2x_vlan_mac_ramrod_params *ramrod =
+                       &vf->op_params.vlan_mac;
+
+               /* set ramrod params */
+               bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+
+               /* set object */
+               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+               /* set extra args */
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+                            struct bnx2x_virtf *vf,
+                            struct bnx2x_vfop_cmd *cmd,
+                            struct bnx2x_vfop_filters *vlans,
+                            int qid, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_vfop_args_filters filters = {
+                       .multi_filter = vlans,
+                       .credit = &bnx2x_vfq(vf, qid, vlan_count),
+               };
+               struct bnx2x_vfop_vlan_mac_flags flags = {
+                       .drv_only = drv_only,
+                       .dont_consume = (filters.credit != NULL),
+                       .single_cmd = false,
+                       .add = false, /* don't care */
+               };
+               struct bnx2x_vlan_mac_ramrod_params *ramrod =
+                       &vf->op_params.vlan_mac;
+
+               /* set ramrod params */
+               bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+
+               /* set object */
+               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+               /* set extra args */
+               filters.multi_filter->add_cnt = vf_vlan_rules_cnt(vf) -
+                       atomic_read(filters.credit);
+
+               vfop->args.filters = filters;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_CONFIG_LIST,
+                                bnx2x_vfop_vlan_mac, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+/* VFOP queue setup (queue constructor + set vlan 0) */
+static void bnx2x_vfop_qsetup(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       int qid = vfop->args.qctor.qid;
+       enum bnx2x_vfop_qsetup_state state = vfop->state;
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vfop_qsetup,
+               .block = false,
+       };
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_QSETUP_CTOR:
+               /* init the queue ctor command */
+               vfop->state = BNX2X_VFOP_QSETUP_VLAN0;
+               vfop->rc = bnx2x_vfop_qctor_cmd(bp, vf, &cmd, qid);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QSETUP_VLAN0:
+               /* skip if non-leading or FPGA/EMU*/
+               if (qid)
+                       goto op_done;
+
+               /* init the queue set-vlan command (for vlan 0) */
+               vfop->state = BNX2X_VFOP_QSETUP_DONE;
+               vfop->rc = bnx2x_vfop_vlan_set_cmd(bp, vf, &cmd, qid, 0, true);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+op_err:
+       BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, vfop->rc);
+op_done:
+       case BNX2X_VFOP_QSETUP_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+}
+
+int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
+                         struct bnx2x_virtf *vf,
+                         struct bnx2x_vfop_cmd *cmd,
+                         int qid)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               vfop->args.qctor.qid = qid;
+
+               bnx2x_vfop_opset(BNX2X_VFOP_QSETUP_CTOR,
+                                bnx2x_vfop_qsetup, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qsetup,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+/* VFOP queue FLR handling (clear vlans, clear macs, queue destructor) */
+static void bnx2x_vfop_qflr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       int qid = vfop->args.qx.qid;
+       enum bnx2x_vfop_qflr_state state = vfop->state;
+       struct bnx2x_queue_state_params *qstate;
+       struct bnx2x_vfop_cmd cmd;
+
+       bnx2x_vfop_reset_wq(vf);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "VF[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       cmd.done = bnx2x_vfop_qflr;
+       cmd.block = false;
+
+       switch (state) {
+       case BNX2X_VFOP_QFLR_CLR_VLAN:
+               /* vlan-clear-all: driver-only, don't consume credit */
+               vfop->state = BNX2X_VFOP_QFLR_CLR_MAC;
+               vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, true);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QFLR_CLR_MAC:
+               /* mac-clear-all: driver only consume credit */
+               vfop->state = BNX2X_VFOP_QFLR_TERMINATE;
+               vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, true);
+               DP(BNX2X_MSG_IOV,
+                  "VF[%d] vfop->rc after bnx2x_vfop_mac_delall_cmd was %d",
+                  vf->abs_vfid, vfop->rc);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QFLR_TERMINATE:
+               qstate = &vfop->op_p->qctor.qstate;
+               memset(qstate , 0, sizeof(*qstate));
+               qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+               vfop->state = BNX2X_VFOP_QFLR_DONE;
+
+               DP(BNX2X_MSG_IOV, "VF[%d] qstate during flr was %d\n",
+                  vf->abs_vfid, qstate->q_obj->state);
+
+               if (qstate->q_obj->state != BNX2X_Q_STATE_RESET) {
+                       qstate->q_obj->state = BNX2X_Q_STATE_STOPPED;
+                       qstate->cmd = BNX2X_Q_CMD_TERMINATE;
+                       vfop->rc = bnx2x_queue_state_change(bp, qstate);
+                       bnx2x_vfop_finalize(vf, vfop->rc, VFOP_VERIFY_PEND);
+               } else {
+                       goto op_done;
+               }
+
+op_err:
+       BNX2X_ERR("QFLR[%d:%d] error: rc %d\n",
+                 vf->abs_vfid, qid, vfop->rc);
+op_done:
+       case BNX2X_VFOP_QFLR_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_pending:
+       return;
+}
+
+static int bnx2x_vfop_qflr_cmd(struct bnx2x *bp,
+                              struct bnx2x_virtf *vf,
+                              struct bnx2x_vfop_cmd *cmd,
+                              int qid)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               vfop->args.qx.qid = qid;
+               bnx2x_vfop_opset(BNX2X_VFOP_QFLR_CLR_VLAN,
+                                bnx2x_vfop_qflr, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qflr,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+/* VFOP multi-casts */
+static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_mcast_ramrod_params *mcast = &vfop->op_p->mcast;
+       struct bnx2x_raw_obj *raw = &mcast->mcast_obj->raw;
+       struct bnx2x_vfop_args_mcast *args = &vfop->args.mc_list;
+       enum bnx2x_vfop_mcast_state state = vfop->state;
+       int i;
+
+       bnx2x_vfop_reset_wq(vf);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_MCAST_DEL:
+               /* clear existing mcasts */
+               vfop->state = BNX2X_VFOP_MCAST_ADD;
+               vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+       case BNX2X_VFOP_MCAST_ADD:
+               if (raw->check_pending(raw))
+                       goto op_pending;
+
+               if (args->mc_num) {
+                       /* update mcast list on the ramrod params */
+                       INIT_LIST_HEAD(&mcast->mcast_list);
+                       for (i = 0; i < args->mc_num; i++)
+                               list_add_tail(&(args->mc[i].link),
+                                             &mcast->mcast_list);
+                       /* add new mcasts */
+                       vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
+                       vfop->rc = bnx2x_config_mcast(bp, mcast,
+                                                     BNX2X_MCAST_CMD_ADD);
+               }
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+       case BNX2X_VFOP_MCAST_CHK_DONE:
+               vfop->rc = raw->check_pending(raw) ? 1 : 0;
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_err:
+       BNX2X_ERR("MCAST CONFIG error: rc %d\n", vfop->rc);
+op_done:
+       kfree(args->mc);
+       bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+       return;
+}
+
+int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd,
+                        bnx2x_mac_addr_t *mcasts,
+                        int mcast_num, bool drv_only)
+{
+       struct bnx2x_vfop *vfop = NULL;
+       size_t mc_sz = mcast_num * sizeof(struct bnx2x_mcast_list_elem);
+       struct bnx2x_mcast_list_elem *mc = mc_sz ? kzalloc(mc_sz, GFP_KERNEL) :
+                                          NULL;
+
+       if (!mc_sz || mc) {
+               vfop = bnx2x_vfop_add(bp, vf);
+               if (vfop) {
+                       int i;
+                       struct bnx2x_mcast_ramrod_params *ramrod =
+                               &vf->op_params.mcast;
+
+                       /* set ramrod params */
+                       memset(ramrod, 0, sizeof(*ramrod));
+                       ramrod->mcast_obj = &vf->mcast_obj;
+                       if (drv_only)
+                               set_bit(RAMROD_DRV_CLR_ONLY,
+                                       &ramrod->ramrod_flags);
+
+                       /* copy mcasts pointers */
+                       vfop->args.mc_list.mc_num = mcast_num;
+                       vfop->args.mc_list.mc = mc;
+                       for (i = 0; i < mcast_num; i++)
+                               mc[i].mac = mcasts[i];
+
+                       bnx2x_vfop_opset(BNX2X_VFOP_MCAST_DEL,
+                                        bnx2x_vfop_mcast, cmd->done);
+                       return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mcast,
+                                                    cmd->block);
+               } else {
+                       kfree(mc);
+               }
+       }
+       return -ENOMEM;
+}
+
+/* VFOP rx-mode */
+static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_rx_mode_ramrod_params *ramrod = &vfop->op_p->rx_mode;
+       enum bnx2x_vfop_rxmode_state state = vfop->state;
+
+       bnx2x_vfop_reset_wq(vf);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_RXMODE_CONFIG:
+               /* next state */
+               vfop->state = BNX2X_VFOP_RXMODE_DONE;
+
+               vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+               BNX2X_ERR("RXMODE error: rc %d\n", vfop->rc);
+op_done:
+       case BNX2X_VFOP_RXMODE_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_pending:
+       return;
+}
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+                         struct bnx2x_virtf *vf,
+                         struct bnx2x_vfop_cmd *cmd,
+                         int qid, unsigned long accept_flags)
+{
+       struct bnx2x_vf_queue *vfq = vfq_get(vf, qid);
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               struct bnx2x_rx_mode_ramrod_params *ramrod =
+                       &vf->op_params.rx_mode;
+
+               memset(ramrod, 0, sizeof(*ramrod));
+
+               /* Prepare ramrod parameters */
+               ramrod->cid = vfq->cid;
+               ramrod->cl_id = vfq_cl_id(vf, vfq);
+               ramrod->rx_mode_obj = &bp->rx_mode_obj;
+               ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid);
+
+               ramrod->rx_accept_flags = accept_flags;
+               ramrod->tx_accept_flags = accept_flags;
+               ramrod->pstate = &vf->filter_state;
+               ramrod->state = BNX2X_FILTER_RX_MODE_PENDING;
+
+               set_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
+               set_bit(RAMROD_RX, &ramrod->ramrod_flags);
+               set_bit(RAMROD_TX, &ramrod->ramrod_flags);
+
+               ramrod->rdata =
+                       bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2);
+               ramrod->rdata_mapping =
+                       bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
+
+               bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
+                                bnx2x_vfop_rxmode, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rxmode,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+/* VFOP queue tear-down ('drop all' rx-mode, clear vlans, clear macs,
+ * queue destructor)
+ */
+static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       int qid = vfop->args.qx.qid;
+       enum bnx2x_vfop_qteardown_state state = vfop->state;
+       struct bnx2x_vfop_cmd cmd;
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       cmd.done = bnx2x_vfop_qdown;
+       cmd.block = false;
+
+       switch (state) {
+       case BNX2X_VFOP_QTEARDOWN_RXMODE:
+               /* Drop all */
+               vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN;
+               vfop->rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd, qid, 0);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QTEARDOWN_CLR_VLAN:
+               /* vlan-clear-all: don't consume credit */
+               vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MAC;
+               vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, false);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QTEARDOWN_CLR_MAC:
+               /* mac-clear-all: consume credit */
+               vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
+               vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, false);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_QTEARDOWN_QDTOR:
+               /* run the queue destruction flow */
+               DP(BNX2X_MSG_IOV, "case: BNX2X_VFOP_QTEARDOWN_QDTOR\n");
+               vfop->state = BNX2X_VFOP_QTEARDOWN_DONE;
+               DP(BNX2X_MSG_IOV, "new state: BNX2X_VFOP_QTEARDOWN_DONE\n");
+               vfop->rc = bnx2x_vfop_qdtor_cmd(bp, vf, &cmd, qid);
+               DP(BNX2X_MSG_IOV, "returned from cmd\n");
+               if (vfop->rc)
+                       goto op_err;
+               return;
+op_err:
+       BNX2X_ERR("QTEARDOWN[%d:%d] error: rc %d\n",
+                 vf->abs_vfid, qid, vfop->rc);
+
+       case BNX2X_VFOP_QTEARDOWN_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+}
+
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd,
+                        int qid)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               vfop->args.qx.qid = qid;
+               bnx2x_vfop_opset(BNX2X_VFOP_QTEARDOWN_RXMODE,
+                                bnx2x_vfop_qdown, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdown,
+                                            cmd->block);
+       }
+
+       return -ENOMEM;
+}
+
+/* VF enable primitives
+ * when pretend is required the caller is responsible
+ * for calling pretend prior to calling these routines
+ */
+
+/* internal vf enable - until vf is enabled internally all transactions
+ * are blocked. this routine should always be called last with pretend.
+ */
+static void bnx2x_vf_enable_internal(struct bnx2x *bp, u8 enable)
+{
+       REG_WR(bp, PGLUE_B_REG_INTERNAL_VFID_ENABLE, enable ? 1 : 0);
+}
+
+/* clears vf error in all semi blocks */
+static void bnx2x_vf_semi_clear_err(struct bnx2x *bp, u8 abs_vfid)
+{
+       REG_WR(bp, TSEM_REG_VFPF_ERR_NUM, abs_vfid);
+       REG_WR(bp, USEM_REG_VFPF_ERR_NUM, abs_vfid);
+       REG_WR(bp, CSEM_REG_VFPF_ERR_NUM, abs_vfid);
+       REG_WR(bp, XSEM_REG_VFPF_ERR_NUM, abs_vfid);
+}
+
+static void bnx2x_vf_pglue_clear_err(struct bnx2x *bp, u8 abs_vfid)
+{
+       u32 was_err_group = (2 * BP_PATH(bp) + abs_vfid) >> 5;
+       u32 was_err_reg = 0;
+
+       switch (was_err_group) {
+       case 0:
+           was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR;
+           break;
+       case 1:
+           was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_63_32_CLR;
+           break;
+       case 2:
+           was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_95_64_CLR;
+           break;
+       case 3:
+           was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_127_96_CLR;
+           break;
+       }
+       REG_WR(bp, was_err_reg, 1 << (abs_vfid & 0x1f));
+}
+
+static void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       int i;
+       u32 val;
+
+       /* Set VF masks and configuration - pretend */
+       bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+
+       REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_LSB, 0);
+       REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_MSB, 0);
+       REG_WR(bp, IGU_REG_SB_MASK_LSB, 0);
+       REG_WR(bp, IGU_REG_SB_MASK_MSB, 0);
+       REG_WR(bp, IGU_REG_PBA_STATUS_LSB, 0);
+       REG_WR(bp, IGU_REG_PBA_STATUS_MSB, 0);
+
+       val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
+       val |= (IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_MSI_MSIX_EN);
+       if (vf->cfg_flags & VF_CFG_INT_SIMD)
+               val |= IGU_VF_CONF_SINGLE_ISR_EN;
+       val &= ~IGU_VF_CONF_PARENT_MASK;
+       val |= BP_FUNC(bp) << IGU_VF_CONF_PARENT_SHIFT; /* parent PF */
+       REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
+
+       DP(BNX2X_MSG_IOV,
+          "value in IGU_REG_VF_CONFIGURATION of vf %d after write %x\n",
+          vf->abs_vfid, REG_RD(bp, IGU_REG_VF_CONFIGURATION));
+
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+       /* iterate over all queues, clear sb consumer */
+       for (i = 0; i < vf_sb_count(vf); i++) {
+               u8 igu_sb_id = vf_igu_sb(vf, i);
+
+               /* zero prod memory */
+               REG_WR(bp, IGU_REG_PROD_CONS_MEMORY + igu_sb_id * 4, 0);
+
+               /* clear sb state machine */
+               bnx2x_igu_clear_sb_gen(bp, vf->abs_vfid, igu_sb_id,
+                                      false /* VF */);
+
+               /* disable + update */
+               bnx2x_vf_igu_ack_sb(bp, vf, igu_sb_id, USTORM_ID, 0,
+                                   IGU_INT_DISABLE, 1);
+       }
+}
+
+void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid)
+{
+       /* set the VF-PF association in the FW */
+       storm_memset_vf_to_pf(bp, FW_VF_HANDLE(abs_vfid), BP_FUNC(bp));
+       storm_memset_func_en(bp, FW_VF_HANDLE(abs_vfid), 1);
+
+       /* clear vf errors*/
+       bnx2x_vf_semi_clear_err(bp, abs_vfid);
+       bnx2x_vf_pglue_clear_err(bp, abs_vfid);
+
+       /* internal vf-enable - pretend */
+       bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, abs_vfid));
+       DP(BNX2X_MSG_IOV, "enabling internal access for vf %x\n", abs_vfid);
+       bnx2x_vf_enable_internal(bp, true);
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static void bnx2x_vf_enable_traffic(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       /* Reset vf in IGU  interrupts are still disabled */
+       bnx2x_vf_igu_reset(bp, vf);
+
+       /* pretend to enable the vf with the PBF */
+       bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+       REG_WR(bp, PBF_REG_DISABLE_VF, 0);
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid)
+{
+       struct pci_dev *dev;
+       struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+
+       if (!vf)
+               goto unknown_dev;
+
+       dev = pci_get_bus_and_slot(vf->bus, vf->devfn);
+       if (dev)
+               return bnx2x_is_pcie_pending(dev);
+
+unknown_dev:
+       BNX2X_ERR("Unknown device\n");
+       return false;
+}
+
+int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
+{
+       /* Wait 100ms */
+       msleep(100);
+
+       /* Verify no pending pci transactions */
+       if (bnx2x_vf_is_pcie_pending(bp, abs_vfid))
+               BNX2X_ERR("PCIE Transactions still pending\n");
+
+       return 0;
+}
+
+/* must be called after the number of PF queues and the number of VFs are
+ * both known
+ */
+static void
+bnx2x_iov_static_resc(struct bnx2x *bp, struct vf_pf_resc_request *resc)
+{
+       u16 vlan_count = 0;
+
+       /* will be set only during VF-ACQUIRE */
+       resc->num_rxqs = 0;
+       resc->num_txqs = 0;
+
+       /* no credit calculcis for macs (just yet) */
+       resc->num_mac_filters = 1;
+
+       /* divvy up vlan rules */
+       vlan_count = bp->vlans_pool.check(&bp->vlans_pool);
+       vlan_count = 1 << ilog2(vlan_count);
+       resc->num_vlan_filters = vlan_count / BNX2X_NR_VIRTFN(bp);
+
+       /* no real limitation */
+       resc->num_mc_filters = 0;
+
+       /* num_sbs already set */
+}
+
+/* FLR routines: */
+static void bnx2x_vf_free_resc(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       /* reset the state variables */
+       bnx2x_iov_static_resc(bp, &vf->alloc_resc);
+       vf->state = VF_FREE;
+}
+
+static void bnx2x_vf_flr_clnup_hw(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       u32 poll_cnt = bnx2x_flr_clnup_poll_count(bp);
+
+       /* DQ usage counter */
+       bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+       bnx2x_flr_clnup_poll_hw_counter(bp, DORQ_REG_VF_USAGE_CNT,
+                                       "DQ VF usage counter timed out",
+                                       poll_cnt);
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+       /* FW cleanup command - poll for the results */
+       if (bnx2x_send_final_clnup(bp, (u8)FW_VF_HANDLE(vf->abs_vfid),
+                                  poll_cnt))
+               BNX2X_ERR("VF[%d] Final cleanup timed-out\n", vf->abs_vfid);
+
+       /* verify TX hw is flushed */
+       bnx2x_tx_hw_flushed(bp, poll_cnt);
+}
+
+static void bnx2x_vfop_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
+       enum bnx2x_vfop_flr_state state = vfop->state;
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vfop_flr,
+               .block = false,
+       };
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_FLR_QUEUES:
+               /* the cleanup operations are valid if and only if the VF
+                * was first acquired.
+                */
+               if (++(qx->qid) < vf_rxq_count(vf)) {
+                       vfop->rc = bnx2x_vfop_qflr_cmd(bp, vf, &cmd,
+                                                      qx->qid);
+                       if (vfop->rc)
+                               goto op_err;
+                       return;
+               }
+               /* remove multicasts */
+               vfop->state = BNX2X_VFOP_FLR_HW;
+               vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL,
+                                               0, true);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+       case BNX2X_VFOP_FLR_HW:
+
+               /* dispatch final cleanup and wait for HW queues to flush */
+               bnx2x_vf_flr_clnup_hw(bp, vf);
+
+               /* release VF resources */
+               bnx2x_vf_free_resc(bp, vf);
+
+               /* re-open the mailbox */
+               bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+
+               goto op_done;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_err:
+       BNX2X_ERR("VF[%d] FLR error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+       vf->flr_clnup_stage = VF_FLR_ACK;
+       bnx2x_vfop_end(bp, vf, vfop);
+       bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
+}
+
+static int bnx2x_vfop_flr_cmd(struct bnx2x *bp,
+                             struct bnx2x_virtf *vf,
+                             vfop_handler_t done)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       if (vfop) {
+               vfop->args.qx.qid = -1; /* loop */
+               bnx2x_vfop_opset(BNX2X_VFOP_FLR_QUEUES,
+                                bnx2x_vfop_flr, done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_flr, false);
+       }
+       return -ENOMEM;
+}
+
+static void bnx2x_vf_flr_clnup(struct bnx2x *bp, struct bnx2x_virtf *prev_vf)
+{
+       int i = prev_vf ? prev_vf->index + 1 : 0;
+       struct bnx2x_virtf *vf;
+
+       /* find next VF to cleanup */
+next_vf_to_clean:
+       for (;
+            i < BNX2X_NR_VIRTFN(bp) &&
+            (bnx2x_vf(bp, i, state) != VF_RESET ||
+             bnx2x_vf(bp, i, flr_clnup_stage) != VF_FLR_CLN);
+            i++)
+               ;
+
+       DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. num of vfs: %d\n", i,
+          BNX2X_NR_VIRTFN(bp));
+
+       if (i < BNX2X_NR_VIRTFN(bp)) {
+               vf = BP_VF(bp, i);
+
+               /* lock the vf pf channel */
+               bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
+
+               /* invoke the VF FLR SM */
+               if (bnx2x_vfop_flr_cmd(bp, vf, bnx2x_vf_flr_clnup)) {
+                       BNX2X_ERR("VF[%d]: FLR cleanup failed -ENOMEM\n",
+                                 vf->abs_vfid);
+
+                       /* mark the VF to be ACKED and continue */
+                       vf->flr_clnup_stage = VF_FLR_ACK;
+                       goto next_vf_to_clean;
+               }
+               return;
+       }
+
+       /* we are done, update vf records */
+       for_each_vf(bp, i) {
+               vf = BP_VF(bp, i);
+
+               if (vf->flr_clnup_stage != VF_FLR_ACK)
+                       continue;
+
+               vf->flr_clnup_stage = VF_FLR_EPILOG;
+       }
+
+       /* Acknowledge the handled VFs.
+        * we are acknowledge all the vfs which an flr was requested for, even
+        * if amongst them there are such that we never opened, since the mcp
+        * will interrupt us immediately again if we only ack some of the bits,
+        * resulting in an endless loop. This can happen for example in KVM
+        * where an 'all ones' flr request is sometimes given by hyper visor
+        */
+       DP(BNX2X_MSG_MCP, "DRV_STATUS_VF_DISABLED ACK for vfs 0x%x 0x%x\n",
+          bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
+       for (i = 0; i < FLRD_VFS_DWORDS; i++)
+               SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i],
+                         bp->vfdb->flrd_vfs[i]);
+
+       bnx2x_fw_command(bp, DRV_MSG_CODE_VF_DISABLED_DONE, 0);
+
+       /* clear the acked bits - better yet if the MCP implemented
+        * write to clear semantics
+        */
+       for (i = 0; i < FLRD_VFS_DWORDS; i++)
+               SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i], 0);
+}
+
+void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
+{
+       int i;
+
+       /* Read FLR'd VFs */
+       for (i = 0; i < FLRD_VFS_DWORDS; i++)
+               bp->vfdb->flrd_vfs[i] = SHMEM2_RD(bp, mcp_vf_disabled[i]);
+
+       DP(BNX2X_MSG_MCP,
+          "DRV_STATUS_VF_DISABLED received for vfs 0x%x 0x%x\n",
+          bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
+
+       for_each_vf(bp, i) {
+               struct bnx2x_virtf *vf = BP_VF(bp, i);
+               u32 reset = 0;
+
+               if (vf->abs_vfid < 32)
+                       reset = bp->vfdb->flrd_vfs[0] & (1 << vf->abs_vfid);
+               else
+                       reset = bp->vfdb->flrd_vfs[1] &
+                               (1 << (vf->abs_vfid - 32));
+
+               if (reset) {
+                       /* set as reset and ready for cleanup */
+                       vf->state = VF_RESET;
+                       vf->flr_clnup_stage = VF_FLR_CLN;
+
+                       DP(BNX2X_MSG_IOV,
+                          "Initiating Final cleanup for VF %d\n",
+                          vf->abs_vfid);
+               }
+       }
+
+       /* do the FLR cleanup for all marked VFs*/
+       bnx2x_vf_flr_clnup(bp, NULL);
+}
+
+/* IOV global initialization routines  */
+void bnx2x_iov_init_dq(struct bnx2x *bp)
+{
+       if (!IS_SRIOV(bp))
+               return;
+
+       /* Set the DQ such that the CID reflect the abs_vfid */
+       REG_WR(bp, DORQ_REG_VF_NORM_VF_BASE, 0);
+       REG_WR(bp, DORQ_REG_MAX_RVFID_SIZE, ilog2(BNX2X_MAX_NUM_OF_VFS));
+
+       /* Set VFs starting CID. If its > 0 the preceding CIDs are belong to
+        * the PF L2 queues
+        */
+       REG_WR(bp, DORQ_REG_VF_NORM_CID_BASE, BNX2X_FIRST_VF_CID);
+
+       /* The VF window size is the log2 of the max number of CIDs per VF */
+       REG_WR(bp, DORQ_REG_VF_NORM_CID_WND_SIZE, BNX2X_VF_CID_WND);
+
+       /* The VF doorbell size  0 - *B, 4 - 128B. We set it here to match
+        * the Pf doorbell size although the 2 are independent.
+        */
+       REG_WR(bp, DORQ_REG_VF_NORM_CID_OFST,
+              BNX2X_DB_SHIFT - BNX2X_DB_MIN_SHIFT);
+
+       /* No security checks for now -
+        * configure single rule (out of 16) mask = 0x1, value = 0x0,
+        * CID range 0 - 0x1ffff
+        */
+       REG_WR(bp, DORQ_REG_VF_TYPE_MASK_0, 1);
+       REG_WR(bp, DORQ_REG_VF_TYPE_VALUE_0, 0);
+       REG_WR(bp, DORQ_REG_VF_TYPE_MIN_MCID_0, 0);
+       REG_WR(bp, DORQ_REG_VF_TYPE_MAX_MCID_0, 0x1ffff);
+
+       /* set the number of VF alllowed doorbells to the full DQ range */
+       REG_WR(bp, DORQ_REG_VF_NORM_MAX_CID_COUNT, 0x20000);
+
+       /* set the VF doorbell threshold */
+       REG_WR(bp, DORQ_REG_VF_USAGE_CT_LIMIT, 4);
+}
+
+void bnx2x_iov_init_dmae(struct bnx2x *bp)
+{
+       DP(BNX2X_MSG_IOV, "SRIOV is %s\n", IS_SRIOV(bp) ? "ON" : "OFF");
+       if (!IS_SRIOV(bp))
+               return;
+
+       REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
+}
+
+static int bnx2x_vf_bus(struct bnx2x *bp, int vfid)
+{
+       struct pci_dev *dev = bp->pdev;
+       struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+       return dev->bus->number + ((dev->devfn + iov->offset +
+                                   iov->stride * vfid) >> 8);
+}
+
+static int bnx2x_vf_devfn(struct bnx2x *bp, int vfid)
+{
+       struct pci_dev *dev = bp->pdev;
+       struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+       return (dev->devfn + iov->offset + iov->stride * vfid) & 0xff;
+}
+
+static void bnx2x_vf_set_bars(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       int i, n;
+       struct pci_dev *dev = bp->pdev;
+       struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+       for (i = 0, n = 0; i < PCI_SRIOV_NUM_BARS; i += 2, n++) {
+               u64 start = pci_resource_start(dev, PCI_IOV_RESOURCES + i);
+               u32 size = pci_resource_len(dev, PCI_IOV_RESOURCES + i);
+
+               size /= iov->total;
+               vf->bars[n].bar = start + size * vf->abs_vfid;
+               vf->bars[n].size = size;
+       }
+}
+
+static int bnx2x_ari_enabled(struct pci_dev *dev)
+{
+       return dev->bus->self && dev->bus->self->ari_enabled;
+}
+
+static void
+bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
+{
+       int sb_id;
+       u32 val;
+       u8 fid;
+
+       /* IGU in normal mode - read CAM */
+       for (sb_id = 0; sb_id < IGU_REG_MAPPING_MEMORY_SIZE; sb_id++) {
+               val = REG_RD(bp, IGU_REG_MAPPING_MEMORY + sb_id * 4);
+               if (!(val & IGU_REG_MAPPING_MEMORY_VALID))
+                       continue;
+               fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID);
+               if (!(fid & IGU_FID_ENCODE_IS_PF))
+                       bnx2x_vf_set_igu_info(bp, sb_id,
+                                             (fid & IGU_FID_VF_NUM_MASK));
+
+               DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n",
+                  ((fid & IGU_FID_ENCODE_IS_PF) ? "PF" : "VF"),
+                  ((fid & IGU_FID_ENCODE_IS_PF) ? (fid & IGU_FID_PF_NUM_MASK) :
+                  (fid & IGU_FID_VF_NUM_MASK)), sb_id,
+                  GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR));
+       }
+}
+
+static void __bnx2x_iov_free_vfdb(struct bnx2x *bp)
+{
+       if (bp->vfdb) {
+               kfree(bp->vfdb->vfqs);
+               kfree(bp->vfdb->vfs);
+               kfree(bp->vfdb);
+       }
+       bp->vfdb = NULL;
+}
+
+static int bnx2x_sriov_pci_cfg_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
+{
+       int pos;
+       struct pci_dev *dev = bp->pdev;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+       if (!pos) {
+               BNX2X_ERR("failed to find SRIOV capability in device\n");
+               return -ENODEV;
+       }
+
+       iov->pos = pos;
+       DP(BNX2X_MSG_IOV, "sriov ext pos %d\n", pos);
+       pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &iov->ctrl);
+       pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &iov->total);
+       pci_read_config_word(dev, pos + PCI_SRIOV_INITIAL_VF, &iov->initial);
+       pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &iov->offset);
+       pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &iov->stride);
+       pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &iov->pgsz);
+       pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
+       pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
+
+       return 0;
+}
+
+static int bnx2x_sriov_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
+{
+       u32 val;
+
+       /* read the SRIOV capability structure
+        * The fields can be read via configuration read or
+        * directly from the device (starting at offset PCICFG_OFFSET)
+        */
+       if (bnx2x_sriov_pci_cfg_info(bp, iov))
+               return -ENODEV;
+
+       /* get the number of SRIOV bars */
+       iov->nres = 0;
+
+       /* read the first_vfid */
+       val = REG_RD(bp, PCICFG_OFFSET + GRC_CONFIG_REG_PF_INIT_VF);
+       iov->first_vf_in_pf = ((val & GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK)
+                              * 8) - (BNX2X_MAX_NUM_OF_VFS * BP_PATH(bp));
+
+       DP(BNX2X_MSG_IOV,
+          "IOV info[%d]: first vf %d, nres %d, cap 0x%x, ctrl 0x%x, total %d, initial %d, num vfs %d, offset %d, stride %d, page size 0x%x\n",
+          BP_FUNC(bp),
+          iov->first_vf_in_pf, iov->nres, iov->cap, iov->ctrl, iov->total,
+          iov->initial, iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz);
+
+       return 0;
+}
+
+static u8 bnx2x_iov_get_max_queue_count(struct bnx2x *bp)
+{
+       int i;
+       u8 queue_count = 0;
+
+       if (IS_SRIOV(bp))
+               for_each_vf(bp, i)
+                       queue_count += bnx2x_vf(bp, i, alloc_resc.num_sbs);
+
+       return queue_count;
+}
+
+/* must be called after PF bars are mapped */
+int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
+                       int num_vfs_param)
+{
+       int err, i, qcount;
+       struct bnx2x_sriov *iov;
+       struct pci_dev *dev = bp->pdev;
+
+       bp->vfdb = NULL;
+
+       /* verify is pf */
+       if (IS_VF(bp))
+               return 0;
+
+       /* verify sriov capability is present in configuration space */
+       if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV))
+               return 0;
+
+       /* verify chip revision */
+       if (CHIP_IS_E1x(bp))
+               return 0;
+
+       /* check if SRIOV support is turned off */
+       if (!num_vfs_param)
+               return 0;
+
+       /* SRIOV assumes that num of PF CIDs < BNX2X_FIRST_VF_CID */
+       if (BNX2X_L2_MAX_CID(bp) >= BNX2X_FIRST_VF_CID) {
+               BNX2X_ERR("PF cids %d are overspilling into vf space (starts at %d). Abort SRIOV\n",
+                         BNX2X_L2_MAX_CID(bp), BNX2X_FIRST_VF_CID);
+               return 0;
+       }
+
+       /* SRIOV can be enabled only with MSIX */
+       if (int_mode_param == BNX2X_INT_MODE_MSI ||
+           int_mode_param == BNX2X_INT_MODE_INTX)
+               BNX2X_ERR("Forced MSI/INTx mode is incompatible with SRIOV\n");
+
+       err = -EIO;
+       /* verify ari is enabled */
+       if (!bnx2x_ari_enabled(bp->pdev)) {
+               BNX2X_ERR("ARI not supported, SRIOV can not be enabled\n");
+               return err;
+       }
+
+       /* verify igu is in normal mode */
+       if (CHIP_INT_MODE_IS_BC(bp)) {
+               BNX2X_ERR("IGU not normal mode,  SRIOV can not be enabled\n");
+               return err;
+       }
+
+       /* allocate the vfs database */
+       bp->vfdb = kzalloc(sizeof(*(bp->vfdb)), GFP_KERNEL);
+       if (!bp->vfdb) {
+               BNX2X_ERR("failed to allocate vf database\n");
+               err = -ENOMEM;
+               goto failed;
+       }
+
+       /* get the sriov info - Linux already collected all the pertinent
+        * information, however the sriov structure is for the private use
+        * of the pci module. Also we want this information regardless
+        * of the hyper-visor.
+        */
+       iov = &(bp->vfdb->sriov);
+       err = bnx2x_sriov_info(bp, iov);
+       if (err)
+               goto failed;
+
+       /* SR-IOV capability was enabled but there are no VFs*/
+       if (iov->total == 0)
+               goto failed;
+
+       /* calculate the actual number of VFs */
+       iov->nr_virtfn = min_t(u16, iov->total, (u16)num_vfs_param);
+
+       /* allocate the vf array */
+       bp->vfdb->vfs = kzalloc(sizeof(struct bnx2x_virtf) *
+                               BNX2X_NR_VIRTFN(bp), GFP_KERNEL);
+       if (!bp->vfdb->vfs) {
+               BNX2X_ERR("failed to allocate vf array\n");
+               err = -ENOMEM;
+               goto failed;
+       }
+
+       /* Initial VF init - index and abs_vfid - nr_virtfn must be set */
+       for_each_vf(bp, i) {
+               bnx2x_vf(bp, i, index) = i;
+               bnx2x_vf(bp, i, abs_vfid) = iov->first_vf_in_pf + i;
+               bnx2x_vf(bp, i, state) = VF_FREE;
+               INIT_LIST_HEAD(&bnx2x_vf(bp, i, op_list_head));
+               mutex_init(&bnx2x_vf(bp, i, op_mutex));
+               bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE;
+       }
+
+       /* re-read the IGU CAM for VFs - index and abs_vfid must be set */
+       bnx2x_get_vf_igu_cam_info(bp);
+
+       /* get the total queue count and allocate the global queue arrays */
+       qcount = bnx2x_iov_get_max_queue_count(bp);
+
+       /* allocate the queue arrays for all VFs */
+       bp->vfdb->vfqs = kzalloc(qcount * sizeof(struct bnx2x_vf_queue),
+                                GFP_KERNEL);
+       if (!bp->vfdb->vfqs) {
+               BNX2X_ERR("failed to allocate vf queue array\n");
+               err = -ENOMEM;
+               goto failed;
+       }
+
+       return 0;
+failed:
+       DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
+       __bnx2x_iov_free_vfdb(bp);
+       return err;
+}
+
+void bnx2x_iov_remove_one(struct bnx2x *bp)
+{
+       /* if SRIOV is not enabled there's nothing to do */
+       if (!IS_SRIOV(bp))
+               return;
+
+       DP(BNX2X_MSG_IOV, "about to call disable sriov\n");
+       pci_disable_sriov(bp->pdev);
+       DP(BNX2X_MSG_IOV, "sriov disabled\n");
+
+       /* free vf database */
+       __bnx2x_iov_free_vfdb(bp);
+}
+
+void bnx2x_iov_free_mem(struct bnx2x *bp)
+{
+       int i;
+
+       if (!IS_SRIOV(bp))
+               return;
+
+       /* free vfs hw contexts */
+       for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+               struct hw_dma *cxt = &bp->vfdb->context[i];
+               BNX2X_PCI_FREE(cxt->addr, cxt->mapping, cxt->size);
+       }
+
+       BNX2X_PCI_FREE(BP_VFDB(bp)->sp_dma.addr,
+                      BP_VFDB(bp)->sp_dma.mapping,
+                      BP_VFDB(bp)->sp_dma.size);
+
+       BNX2X_PCI_FREE(BP_VF_MBX_DMA(bp)->addr,
+                      BP_VF_MBX_DMA(bp)->mapping,
+                      BP_VF_MBX_DMA(bp)->size);
+
+       BNX2X_PCI_FREE(BP_VF_BULLETIN_DMA(bp)->addr,
+                      BP_VF_BULLETIN_DMA(bp)->mapping,
+                      BP_VF_BULLETIN_DMA(bp)->size);
+}
+
+int bnx2x_iov_alloc_mem(struct bnx2x *bp)
+{
+       size_t tot_size;
+       int i, rc = 0;
+
+       if (!IS_SRIOV(bp))
+               return rc;
+
+       /* allocate vfs hw contexts */
+       tot_size = (BP_VFDB(bp)->sriov.first_vf_in_pf + BNX2X_NR_VIRTFN(bp)) *
+               BNX2X_CIDS_PER_VF * sizeof(union cdu_context);
+
+       for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+               struct hw_dma *cxt = BP_VF_CXT_PAGE(bp, i);
+               cxt->size = min_t(size_t, tot_size, CDU_ILT_PAGE_SZ);
+
+               if (cxt->size) {
+                       BNX2X_PCI_ALLOC(cxt->addr, &cxt->mapping, cxt->size);
+               } else {
+                       cxt->addr = NULL;
+                       cxt->mapping = 0;
+               }
+               tot_size -= cxt->size;
+       }
+
+       /* allocate vfs ramrods dma memory - client_init and set_mac */
+       tot_size = BNX2X_NR_VIRTFN(bp) * sizeof(struct bnx2x_vf_sp);
+       BNX2X_PCI_ALLOC(BP_VFDB(bp)->sp_dma.addr, &BP_VFDB(bp)->sp_dma.mapping,
+                       tot_size);
+       BP_VFDB(bp)->sp_dma.size = tot_size;
+
+       /* allocate mailboxes */
+       tot_size = BNX2X_NR_VIRTFN(bp) * MBX_MSG_ALIGNED_SIZE;
+       BNX2X_PCI_ALLOC(BP_VF_MBX_DMA(bp)->addr, &BP_VF_MBX_DMA(bp)->mapping,
+                       tot_size);
+       BP_VF_MBX_DMA(bp)->size = tot_size;
+
+       /* allocate local bulletin boards */
+       tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE;
+       BNX2X_PCI_ALLOC(BP_VF_BULLETIN_DMA(bp)->addr,
+                       &BP_VF_BULLETIN_DMA(bp)->mapping, tot_size);
+       BP_VF_BULLETIN_DMA(bp)->size = tot_size;
+
+       return 0;
+
+alloc_mem_err:
+       return -ENOMEM;
+}
+
+static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                          struct bnx2x_vf_queue *q)
+{
+       u8 cl_id = vfq_cl_id(vf, q);
+       u8 func_id = FW_VF_HANDLE(vf->abs_vfid);
+       unsigned long q_type = 0;
+
+       set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+       set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+
+       /* Queue State object */
+       bnx2x_init_queue_obj(bp, &q->sp_obj,
+                            cl_id, &q->cid, 1, func_id,
+                            bnx2x_vf_sp(bp, vf, q_data),
+                            bnx2x_vf_sp_map(bp, vf, q_data),
+                            q_type);
+
+       DP(BNX2X_MSG_IOV,
+          "initialized vf %d's queue object. func id set to %d\n",
+          vf->abs_vfid, q->sp_obj.func_id);
+
+       /* mac/vlan objects are per queue, but only those
+        * that belong to the leading queue are initialized
+        */
+       if (vfq_is_leading(q)) {
+               /* mac */
+               bnx2x_init_mac_obj(bp, &q->mac_obj,
+                                  cl_id, q->cid, func_id,
+                                  bnx2x_vf_sp(bp, vf, mac_rdata),
+                                  bnx2x_vf_sp_map(bp, vf, mac_rdata),
+                                  BNX2X_FILTER_MAC_PENDING,
+                                  &vf->filter_state,
+                                  BNX2X_OBJ_TYPE_RX_TX,
+                                  &bp->macs_pool);
+               /* vlan */
+               bnx2x_init_vlan_obj(bp, &q->vlan_obj,
+                                   cl_id, q->cid, func_id,
+                                   bnx2x_vf_sp(bp, vf, vlan_rdata),
+                                   bnx2x_vf_sp_map(bp, vf, vlan_rdata),
+                                   BNX2X_FILTER_VLAN_PENDING,
+                                   &vf->filter_state,
+                                   BNX2X_OBJ_TYPE_RX_TX,
+                                   &bp->vlans_pool);
+
+               /* mcast */
+               bnx2x_init_mcast_obj(bp, &vf->mcast_obj, cl_id,
+                                    q->cid, func_id, func_id,
+                                    bnx2x_vf_sp(bp, vf, mcast_rdata),
+                                    bnx2x_vf_sp_map(bp, vf, mcast_rdata),
+                                    BNX2X_FILTER_MCAST_PENDING,
+                                    &vf->filter_state,
+                                    BNX2X_OBJ_TYPE_RX_TX);
+
+               vf->leading_rss = cl_id;
+       }
+}
+
+/* called by bnx2x_nic_load */
+int bnx2x_iov_nic_init(struct bnx2x *bp)
+{
+       int vfid, qcount, i;
+
+       if (!IS_SRIOV(bp)) {
+               DP(BNX2X_MSG_IOV, "vfdb was not allocated\n");
+               return 0;
+       }
+
+       DP(BNX2X_MSG_IOV, "num of vfs: %d\n", (bp)->vfdb->sriov.nr_virtfn);
+
+       /* initialize vf database */
+       for_each_vf(bp, vfid) {
+               struct bnx2x_virtf *vf = BP_VF(bp, vfid);
+
+               int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vfid) *
+                       BNX2X_CIDS_PER_VF;
+
+               union cdu_context *base_cxt = (union cdu_context *)
+                       BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
+                       (base_vf_cid & (ILT_PAGE_CIDS-1));
+
+               DP(BNX2X_MSG_IOV,
+                  "VF[%d] Max IGU SBs: %d, base vf cid 0x%x, base cid 0x%x, base cxt %p\n",
+                  vf->abs_vfid, vf_sb_count(vf), base_vf_cid,
+                  BNX2X_FIRST_VF_CID + base_vf_cid, base_cxt);
+
+               /* init statically provisioned resources */
+               bnx2x_iov_static_resc(bp, &vf->alloc_resc);
+
+               /* queues are initialized during VF-ACQUIRE */
+
+               /* reserve the vf vlan credit */
+               bp->vlans_pool.get(&bp->vlans_pool, vf_vlan_rules_cnt(vf));
+
+               vf->filter_state = 0;
+               vf->sp_cl_id = bnx2x_fp(bp, 0, cl_id);
+
+               /*  init mcast object - This object will be re-initialized
+                *  during VF-ACQUIRE with the proper cl_id and cid.
+                *  It needs to be initialized here so that it can be safely
+                *  handled by a subsequent FLR flow.
+                */
+               bnx2x_init_mcast_obj(bp, &vf->mcast_obj, 0xFF,
+                                    0xFF, 0xFF, 0xFF,
+                                    bnx2x_vf_sp(bp, vf, mcast_rdata),
+                                    bnx2x_vf_sp_map(bp, vf, mcast_rdata),
+                                    BNX2X_FILTER_MCAST_PENDING,
+                                    &vf->filter_state,
+                                    BNX2X_OBJ_TYPE_RX_TX);
+
+               /* set the mailbox message addresses */
+               BP_VF_MBX(bp, vfid)->msg = (struct bnx2x_vf_mbx_msg *)
+                       (((u8 *)BP_VF_MBX_DMA(bp)->addr) + vfid *
+                       MBX_MSG_ALIGNED_SIZE);
+
+               BP_VF_MBX(bp, vfid)->msg_mapping = BP_VF_MBX_DMA(bp)->mapping +
+                       vfid * MBX_MSG_ALIGNED_SIZE;
+
+               /* Enable vf mailbox */
+               bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+       }
+
+       /* Final VF init */
+       qcount = 0;
+       for_each_vf(bp, i) {
+               struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+               /* fill in the BDF and bars */
+               vf->bus = bnx2x_vf_bus(bp, i);
+               vf->devfn = bnx2x_vf_devfn(bp, i);
+               bnx2x_vf_set_bars(bp, vf);
+
+               DP(BNX2X_MSG_IOV,
+                  "VF info[%d]: bus 0x%x, devfn 0x%x, bar0 [0x%x, %d], bar1 [0x%x, %d], bar2 [0x%x, %d]\n",
+                  vf->abs_vfid, vf->bus, vf->devfn,
+                  (unsigned)vf->bars[0].bar, vf->bars[0].size,
+                  (unsigned)vf->bars[1].bar, vf->bars[1].size,
+                  (unsigned)vf->bars[2].bar, vf->bars[2].size);
+
+               /* set local queue arrays */
+               vf->vfqs = &bp->vfdb->vfqs[qcount];
+               qcount += bnx2x_vf(bp, i, alloc_resc.num_sbs);
+       }
+
+       return 0;
+}
+
+/* called by bnx2x_chip_cleanup */
+int bnx2x_iov_chip_cleanup(struct bnx2x *bp)
+{
+       int i;
+
+       if (!IS_SRIOV(bp))
+               return 0;
+
+       /* release all the VFs */
+       for_each_vf(bp, i)
+               bnx2x_vf_release(bp, BP_VF(bp, i), true); /* blocking */
+
+       return 0;
+}
+
+/* called by bnx2x_init_hw_func, returns the next ilt line */
+int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line)
+{
+       int i;
+       struct bnx2x_ilt *ilt = BP_ILT(bp);
+
+       if (!IS_SRIOV(bp))
+               return line;
+
+       /* set vfs ilt lines */
+       for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+               struct hw_dma *hw_cxt = BP_VF_CXT_PAGE(bp, i);
+
+               ilt->lines[line+i].page = hw_cxt->addr;
+               ilt->lines[line+i].page_mapping = hw_cxt->mapping;
+               ilt->lines[line+i].size = hw_cxt->size; /* doesn't matter */
+       }
+       return line + i;
+}
+
+static u8 bnx2x_iov_is_vf_cid(struct bnx2x *bp, u16 cid)
+{
+       return ((cid >= BNX2X_FIRST_VF_CID) &&
+               ((cid - BNX2X_FIRST_VF_CID) < BNX2X_VF_CIDS));
+}
+
+static
+void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
+                                       struct bnx2x_vf_queue *vfq,
+                                       union event_ring_elem *elem)
+{
+       unsigned long ramrod_flags = 0;
+       int rc = 0;
+
+       /* Always push next commands out, don't wait here */
+       set_bit(RAMROD_CONT, &ramrod_flags);
+
+       switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+       case BNX2X_FILTER_MAC_PENDING:
+               rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem,
+                                          &ramrod_flags);
+               break;
+       case BNX2X_FILTER_VLAN_PENDING:
+               rc = vfq->vlan_obj.complete(bp, &vfq->vlan_obj, elem,
+                                           &ramrod_flags);
+               break;
+       default:
+               BNX2X_ERR("Unsupported classification command: %d\n",
+                         elem->message.data.eth_event.echo);
+               return;
+       }
+       if (rc < 0)
+               BNX2X_ERR("Failed to schedule new commands: %d\n", rc);
+       else if (rc > 0)
+               DP(BNX2X_MSG_IOV, "Scheduled next pending commands...\n");
+}
+
+static
+void bnx2x_vf_handle_mcast_eqe(struct bnx2x *bp,
+                              struct bnx2x_virtf *vf)
+{
+       struct bnx2x_mcast_ramrod_params rparam = {NULL};
+       int rc;
+
+       rparam.mcast_obj = &vf->mcast_obj;
+       vf->mcast_obj.raw.clear_pending(&vf->mcast_obj.raw);
+
+       /* If there are pending mcast commands - send them */
+       if (vf->mcast_obj.check_pending(&vf->mcast_obj)) {
+               rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
+               if (rc < 0)
+                       BNX2X_ERR("Failed to send pending mcast commands: %d\n",
+                                 rc);
+       }
+}
+
+static
+void bnx2x_vf_handle_filters_eqe(struct bnx2x *bp,
+                                struct bnx2x_virtf *vf)
+{
+       smp_mb__before_clear_bit();
+       clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
+       smp_mb__after_clear_bit();
+}
+
+int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
+{
+       struct bnx2x_virtf *vf;
+       int qidx = 0, abs_vfid;
+       u8 opcode;
+       u16 cid = 0xffff;
+
+       if (!IS_SRIOV(bp))
+               return 1;
+
+       /* first get the cid - the only events we handle here are cfc-delete
+        * and set-mac completion
+        */
+       opcode = elem->message.opcode;
+
+       switch (opcode) {
+       case EVENT_RING_OPCODE_CFC_DEL:
+               cid = SW_CID((__force __le32)
+                            elem->message.data.cfc_del_event.cid);
+               DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid);
+               break;
+       case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
+       case EVENT_RING_OPCODE_MULTICAST_RULES:
+       case EVENT_RING_OPCODE_FILTERS_RULES:
+               cid = (elem->message.data.eth_event.echo &
+                      BNX2X_SWCID_MASK);
+               DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
+               break;
+       case EVENT_RING_OPCODE_VF_FLR:
+               abs_vfid = elem->message.data.vf_flr_event.vf_id;
+               DP(BNX2X_MSG_IOV, "Got VF FLR notification abs_vfid=%d\n",
+                  abs_vfid);
+               goto get_vf;
+       case EVENT_RING_OPCODE_MALICIOUS_VF:
+               abs_vfid = elem->message.data.malicious_vf_event.vf_id;
+               DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d\n",
+                  abs_vfid);
+               goto get_vf;
+       default:
+               return 1;
+       }
+
+       /* check if the cid is the VF range */
+       if (!bnx2x_iov_is_vf_cid(bp, cid)) {
+               DP(BNX2X_MSG_IOV, "cid is outside vf range: %d\n", cid);
+               return 1;
+       }
+
+       /* extract vf and rxq index from vf_cid - relies on the following:
+        * 1. vfid on cid reflects the true abs_vfid
+        * 2. the max number of VFs (per path) is 64
+        */
+       qidx = cid & ((1 << BNX2X_VF_CID_WND)-1);
+       abs_vfid = (cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
+get_vf:
+       vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+
+       if (!vf) {
+               BNX2X_ERR("EQ completion for unknown VF, cid %d, abs_vfid %d\n",
+                         cid, abs_vfid);
+               return 0;
+       }
+
+       switch (opcode) {
+       case EVENT_RING_OPCODE_CFC_DEL:
+               DP(BNX2X_MSG_IOV, "got VF [%d:%d] cfc delete ramrod\n",
+                  vf->abs_vfid, qidx);
+               vfq_get(vf, qidx)->sp_obj.complete_cmd(bp,
+                                                      &vfq_get(vf,
+                                                               qidx)->sp_obj,
+                                                      BNX2X_Q_CMD_CFC_DEL);
+               break;
+       case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
+               DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mac/vlan ramrod\n",
+                  vf->abs_vfid, qidx);
+               bnx2x_vf_handle_classification_eqe(bp, vfq_get(vf, qidx), elem);
+               break;
+       case EVENT_RING_OPCODE_MULTICAST_RULES:
+               DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mcast ramrod\n",
+                  vf->abs_vfid, qidx);
+               bnx2x_vf_handle_mcast_eqe(bp, vf);
+               break;
+       case EVENT_RING_OPCODE_FILTERS_RULES:
+               DP(BNX2X_MSG_IOV, "got VF [%d:%d] set rx-mode ramrod\n",
+                  vf->abs_vfid, qidx);
+               bnx2x_vf_handle_filters_eqe(bp, vf);
+               break;
+       case EVENT_RING_OPCODE_VF_FLR:
+               DP(BNX2X_MSG_IOV, "got VF [%d] FLR notification\n",
+                  vf->abs_vfid);
+               /* Do nothing for now */
+               break;
+       case EVENT_RING_OPCODE_MALICIOUS_VF:
+               DP(BNX2X_MSG_IOV, "got VF [%d] MALICIOUS notification\n",
+                  vf->abs_vfid);
+               /* Do nothing for now */
+               break;
+       }
+       /* SRIOV: reschedule any 'in_progress' operations */
+       bnx2x_iov_sp_event(bp, cid, false);
+
+       return 0;
+}
+
+static struct bnx2x_virtf *bnx2x_vf_by_cid(struct bnx2x *bp, int vf_cid)
+{
+       /* extract the vf from vf_cid - relies on the following:
+        * 1. vfid on cid reflects the true abs_vfid
+        * 2. the max number of VFs (per path) is 64
+        */
+       int abs_vfid = (vf_cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
+       return bnx2x_vf_by_abs_fid(bp, abs_vfid);
+}
+
+void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+                               struct bnx2x_queue_sp_obj **q_obj)
+{
+       struct bnx2x_virtf *vf;
+
+       if (!IS_SRIOV(bp))
+               return;
+
+       vf = bnx2x_vf_by_cid(bp, vf_cid);
+
+       if (vf) {
+               /* extract queue index from vf_cid - relies on the following:
+                * 1. vfid on cid reflects the true abs_vfid
+                * 2. the max number of VFs (per path) is 64
+                */
+               int q_index = vf_cid & ((1 << BNX2X_VF_CID_WND)-1);
+               *q_obj = &bnx2x_vfq(vf, q_index, sp_obj);
+       } else {
+               BNX2X_ERR("No vf matching cid %d\n", vf_cid);
+       }
+}
+
+void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
+{
+       struct bnx2x_virtf *vf;
+
+       /* check if the cid is the VF range */
+       if (!IS_SRIOV(bp) || !bnx2x_iov_is_vf_cid(bp, vf_cid))
+               return;
+
+       vf = bnx2x_vf_by_cid(bp, vf_cid);
+       if (vf) {
+               /* set in_progress flag */
+               atomic_set(&vf->op_in_progress, 1);
+               if (queue_work)
+                       queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+       }
+}
+
+void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
+{
+       int i;
+       int first_queue_query_index, num_queues_req;
+       dma_addr_t cur_data_offset;
+       struct stats_query_entry *cur_query_entry;
+       u8 stats_count = 0;
+       bool is_fcoe = false;
+
+       if (!IS_SRIOV(bp))
+               return;
+
+       if (!NO_FCOE(bp))
+               is_fcoe = true;
+
+       /* fcoe adds one global request and one queue request */
+       num_queues_req = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe;
+       first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
+               (is_fcoe ? 0 : 1);
+
+       DP(BNX2X_MSG_IOV,
+          "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
+          BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
+          first_queue_query_index + num_queues_req);
+
+       cur_data_offset = bp->fw_stats_data_mapping +
+               offsetof(struct bnx2x_fw_stats_data, queue_stats) +
+               num_queues_req * sizeof(struct per_queue_stats);
+
+       cur_query_entry = &bp->fw_stats_req->
+               query[first_queue_query_index + num_queues_req];
+
+       for_each_vf(bp, i) {
+               int j;
+               struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+               if (vf->state != VF_ENABLED) {
+                       DP(BNX2X_MSG_IOV,
+                          "vf %d not enabled so no stats for it\n",
+                          vf->abs_vfid);
+                       continue;
+               }
+
+               DP(BNX2X_MSG_IOV, "add addresses for vf %d\n", vf->abs_vfid);
+               for_each_vfq(vf, j) {
+                       struct bnx2x_vf_queue *rxq = vfq_get(vf, j);
+
+                       /* collect stats fro active queues only */
+                       if (bnx2x_get_q_logical_state(bp, &rxq->sp_obj) ==
+                           BNX2X_Q_LOGICAL_STATE_STOPPED)
+                               continue;
+
+                       /* create stats query entry for this queue */
+                       cur_query_entry->kind = STATS_TYPE_QUEUE;
+                       cur_query_entry->index = vfq_cl_id(vf, rxq);
+                       cur_query_entry->funcID =
+                               cpu_to_le16(FW_VF_HANDLE(vf->abs_vfid));
+                       cur_query_entry->address.hi =
+                               cpu_to_le32(U64_HI(vf->fw_stat_map));
+                       cur_query_entry->address.lo =
+                               cpu_to_le32(U64_LO(vf->fw_stat_map));
+                       DP(BNX2X_MSG_IOV,
+                          "added address %x %x for vf %d queue %d client %d\n",
+                          cur_query_entry->address.hi,
+                          cur_query_entry->address.lo, cur_query_entry->funcID,
+                          j, cur_query_entry->index);
+                       cur_query_entry++;
+                       cur_data_offset += sizeof(struct per_queue_stats);
+                       stats_count++;
+               }
+       }
+       bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
+}
+
+void bnx2x_iov_sp_task(struct bnx2x *bp)
+{
+       int i;
+
+       if (!IS_SRIOV(bp))
+               return;
+       /* Iterate over all VFs and invoke state transition for VFs with
+        * 'in-progress' slow-path operations
+        */
+       DP(BNX2X_MSG_IOV, "searching for pending vf operations\n");
+       for_each_vf(bp, i) {
+               struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+               if (!list_empty(&vf->op_list_head) &&
+                   atomic_read(&vf->op_in_progress)) {
+                       DP(BNX2X_MSG_IOV, "running pending op for vf %d\n", i);
+                       bnx2x_vfop_cur(bp, vf)->transition(bp, vf);
+               }
+       }
+}
+
+static inline
+struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
+{
+       int i;
+       struct bnx2x_virtf *vf = NULL;
+
+       for_each_vf(bp, i) {
+               vf = BP_VF(bp, i);
+               if (stat_id >= vf->igu_base_id &&
+                   stat_id < vf->igu_base_id + vf_sb_count(vf))
+                       break;
+       }
+       return vf;
+}
+
+/* VF API helpers */
+static void bnx2x_vf_qtbl_set_q(struct bnx2x *bp, u8 abs_vfid, u8 qid,
+                               u8 enable)
+{
+       u32 reg = PXP_REG_HST_ZONE_PERMISSION_TABLE + qid * 4;
+       u32 val = enable ? (abs_vfid | (1 << 6)) : 0;
+
+       REG_WR(bp, reg, val);
+}
+
+static void bnx2x_vf_clr_qtbl(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       int i;
+
+       for_each_vfq(vf, i)
+               bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
+                                   vfq_qzone_id(vf, vfq_get(vf, i)), false);
+}
+
+static void bnx2x_vf_igu_disable(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       u32 val;
+
+       /* clear the VF configuration - pretend */
+       bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+       val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
+       val &= ~(IGU_VF_CONF_MSI_MSIX_EN | IGU_VF_CONF_SINGLE_ISR_EN |
+                IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_PARENT_MASK);
+       REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
+       bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       return min_t(u8, min_t(u8, vf_sb_count(vf), BNX2X_CIDS_PER_VF),
+                    BNX2X_VF_MAX_QUEUES);
+}
+
+static
+int bnx2x_vf_chk_avail_resc(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                           struct vf_pf_resc_request *req_resc)
+{
+       u8 rxq_cnt = vf_rxq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
+       u8 txq_cnt = vf_txq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
+
+       return ((req_resc->num_rxqs <= rxq_cnt) &&
+               (req_resc->num_txqs <= txq_cnt) &&
+               (req_resc->num_sbs <= vf_sb_count(vf))   &&
+               (req_resc->num_mac_filters <= vf_mac_rules_cnt(vf)) &&
+               (req_resc->num_vlan_filters <= vf_vlan_rules_cnt(vf)));
+}
+
+/* CORE VF API */
+int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                    struct vf_pf_resc_request *resc)
+{
+       int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vf->index) *
+               BNX2X_CIDS_PER_VF;
+
+       union cdu_context *base_cxt = (union cdu_context *)
+               BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
+               (base_vf_cid & (ILT_PAGE_CIDS-1));
+       int i;
+
+       /* if state is 'acquired' the VF was not released or FLR'd, in
+        * this case the returned resources match the acquired already
+        * acquired resources. Verify that the requested numbers do
+        * not exceed the already acquired numbers.
+        */
+       if (vf->state == VF_ACQUIRED) {
+               DP(BNX2X_MSG_IOV, "VF[%d] Trying to re-acquire resources (VF was not released or FLR'd)\n",
+                  vf->abs_vfid);
+
+               if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
+                       BNX2X_ERR("VF[%d] When re-acquiring resources, requested numbers must be <= then previously acquired numbers\n",
+                                 vf->abs_vfid);
+                       return -EINVAL;
+               }
+               return 0;
+       }
+
+       /* Otherwise vf state must be 'free' or 'reset' */
+       if (vf->state != VF_FREE && vf->state != VF_RESET) {
+               BNX2X_ERR("VF[%d] Can not acquire a VF with state %d\n",
+                         vf->abs_vfid, vf->state);
+               return -EINVAL;
+       }
+
+       /* static allocation:
+        * the global maximum number are fixed per VF. fail the request if
+        * requested number exceed these globals
+        */
+       if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
+               DP(BNX2X_MSG_IOV,
+                  "cannot fulfill vf resource request. Placing maximal available values in response\n");
+               /* set the max resource in the vf */
+               return -ENOMEM;
+       }
+
+       /* Set resources counters - 0 request means max available */
+       vf_sb_count(vf) = resc->num_sbs;
+       vf_rxq_count(vf) = resc->num_rxqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
+       vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
+       if (resc->num_mac_filters)
+               vf_mac_rules_cnt(vf) = resc->num_mac_filters;
+       if (resc->num_vlan_filters)
+               vf_vlan_rules_cnt(vf) = resc->num_vlan_filters;
+
+       DP(BNX2X_MSG_IOV,
+          "Fulfilling vf request: sb count %d, tx_count %d, rx_count %d, mac_rules_count %d, vlan_rules_count %d\n",
+          vf_sb_count(vf), vf_rxq_count(vf),
+          vf_txq_count(vf), vf_mac_rules_cnt(vf),
+          vf_vlan_rules_cnt(vf));
+
+       /* Initialize the queues */
+       if (!vf->vfqs) {
+               DP(BNX2X_MSG_IOV, "vf->vfqs was not allocated\n");
+               return -EINVAL;
+       }
+
+       for_each_vfq(vf, i) {
+               struct bnx2x_vf_queue *q = vfq_get(vf, i);
+
+               if (!q) {
+                       DP(BNX2X_MSG_IOV, "q number %d was not allocated\n", i);
+                       return -EINVAL;
+               }
+
+               q->index = i;
+               q->cxt = &((base_cxt + i)->eth);
+               q->cid = BNX2X_FIRST_VF_CID + base_vf_cid + i;
+
+               DP(BNX2X_MSG_IOV, "VFQ[%d:%d]: index %d, cid 0x%x, cxt %p\n",
+                  vf->abs_vfid, i, q->index, q->cid, q->cxt);
+
+               /* init SP objects */
+               bnx2x_vfq_init(bp, vf, q);
+       }
+       vf->state = VF_ACQUIRED;
+       return 0;
+}
+
+int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map)
+{
+       struct bnx2x_func_init_params func_init = {0};
+       u16 flags = 0;
+       int i;
+
+       /* the sb resources are initialized at this point, do the
+        * FW/HW initializations
+        */
+       for_each_vf_sb(vf, i)
+               bnx2x_init_sb(bp, (dma_addr_t)sb_map[i], vf->abs_vfid, true,
+                             vf_igu_sb(vf, i), vf_igu_sb(vf, i));
+
+       /* Sanity checks */
+       if (vf->state != VF_ACQUIRED) {
+               DP(BNX2X_MSG_IOV, "VF[%d] is not in VF_ACQUIRED, but %d\n",
+                  vf->abs_vfid, vf->state);
+               return -EINVAL;
+       }
+       /* FLR cleanup epilogue */
+       if (bnx2x_vf_flr_clnup_epilog(bp, vf->abs_vfid))
+               return -EBUSY;
+
+       /* reset IGU VF statistics: MSIX */
+       REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT + vf->abs_vfid * 4 , 0);
+
+       /* vf init */
+       if (vf->cfg_flags & VF_CFG_STATS)
+               flags |= (FUNC_FLG_STATS | FUNC_FLG_SPQ);
+
+       if (vf->cfg_flags & VF_CFG_TPA)
+               flags |= FUNC_FLG_TPA;
+
+       if (is_vf_multi(vf))
+               flags |= FUNC_FLG_RSS;
+
+       /* function setup */
+       func_init.func_flgs = flags;
+       func_init.pf_id = BP_FUNC(bp);
+       func_init.func_id = FW_VF_HANDLE(vf->abs_vfid);
+       func_init.fw_stat_map = vf->fw_stat_map;
+       func_init.spq_map = vf->spq_map;
+       func_init.spq_prod = 0;
+       bnx2x_func_init(bp, &func_init);
+
+       /* Enable the vf */
+       bnx2x_vf_enable_access(bp, vf->abs_vfid);
+       bnx2x_vf_enable_traffic(bp, vf);
+
+       /* queue protection table */
+       for_each_vfq(vf, i)
+               bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
+                                   vfq_qzone_id(vf, vfq_get(vf, i)), true);
+
+       vf->state = VF_ENABLED;
+
+       /* update vf bulletin board */
+       bnx2x_post_vf_bulletin(bp, vf->index);
+
+       return 0;
+}
+
+/* VFOP close (teardown the queues, delete mcasts and close HW) */
+static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
+       enum bnx2x_vfop_close_state state = vfop->state;
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vfop_close,
+               .block = false,
+       };
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+       switch (state) {
+       case BNX2X_VFOP_CLOSE_QUEUES:
+
+               if (++(qx->qid) < vf_rxq_count(vf)) {
+                       vfop->rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qx->qid);
+                       if (vfop->rc)
+                               goto op_err;
+                       return;
+               }
+
+               /* remove multicasts */
+               vfop->state = BNX2X_VFOP_CLOSE_HW;
+               vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL, 0, false);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case BNX2X_VFOP_CLOSE_HW:
+
+               /* disable the interrupts */
+               DP(BNX2X_MSG_IOV, "disabling igu\n");
+               bnx2x_vf_igu_disable(bp, vf);
+
+               /* disable the VF */
+               DP(BNX2X_MSG_IOV, "clearing qtbl\n");
+               bnx2x_vf_clr_qtbl(bp, vf);
+
+               goto op_done;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_err:
+       BNX2X_ERR("VF[%d] CLOSE error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+       vf->state = VF_ACQUIRED;
+       DP(BNX2X_MSG_IOV, "set state to acquired\n");
+       bnx2x_vfop_end(bp, vf, vfop);
+}
+
+int bnx2x_vfop_close_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       if (vfop) {
+               vfop->args.qx.qid = -1; /* loop */
+               bnx2x_vfop_opset(BNX2X_VFOP_CLOSE_QUEUES,
+                                bnx2x_vfop_close, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_close,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+/* VF release can be called either: 1. the VF was acquired but
+ * not enabled 2. the vf was enabled or in the process of being
+ * enabled
+ */
+static void bnx2x_vfop_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vfop_release,
+               .block = false,
+       };
+
+       DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "VF[%d] STATE: %s\n", vf->abs_vfid,
+          vf->state == VF_FREE ? "Free" :
+          vf->state == VF_ACQUIRED ? "Acquired" :
+          vf->state == VF_ENABLED ? "Enabled" :
+          vf->state == VF_RESET ? "Reset" :
+          "Unknown");
+
+       switch (vf->state) {
+       case VF_ENABLED:
+               vfop->rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
+               if (vfop->rc)
+                       goto op_err;
+               return;
+
+       case VF_ACQUIRED:
+               DP(BNX2X_MSG_IOV, "about to free resources\n");
+               bnx2x_vf_free_resc(bp, vf);
+               DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
+               goto op_done;
+
+       case VF_FREE:
+       case VF_RESET:
+               /* do nothing */
+               goto op_done;
+       default:
+               bnx2x_vfop_default(vf->state);
+       }
+op_err:
+       BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+       bnx2x_vfop_end(bp, vf, vfop);
+}
+
+int bnx2x_vfop_release_cmd(struct bnx2x *bp,
+                          struct bnx2x_virtf *vf,
+                          struct bnx2x_vfop_cmd *cmd)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       if (vfop) {
+               bnx2x_vfop_opset(-1, /* use vf->state */
+                                bnx2x_vfop_release, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_release,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+/* VF release ~ VF close + VF release-resources
+ * Release is the ultimate SW shutdown and is called whenever an
+ * irrecoverable error is encountered.
+ */
+void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block)
+{
+       struct bnx2x_vfop_cmd cmd = {
+               .done = NULL,
+               .block = block,
+       };
+       int rc;
+       bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+
+       rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+       if (rc)
+               WARN(rc,
+                    "VF[%d] Failed to allocate resources for release op- rc=%d\n",
+                    vf->abs_vfid, rc);
+}
+
+static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
+                             struct bnx2x_virtf *vf, u32 *sbdf)
+{
+       *sbdf = vf->devfn | (vf->bus << 8);
+}
+
+static inline void bnx2x_vf_get_bars(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                      struct bnx2x_vf_bar_info *bar_info)
+{
+       int n;
+
+       bar_info->nr_bars = bp->vfdb->sriov.nres;
+       for (n = 0; n < bar_info->nr_bars; n++)
+               bar_info->bars[n] = vf->bars[n];
+}
+
+void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                             enum channel_tlvs tlv)
+{
+       /* lock the channel */
+       mutex_lock(&vf->op_mutex);
+
+       /* record the locking op */
+       vf->op_current = tlv;
+
+       /* log the lock */
+       DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel locked by %d\n",
+          vf->abs_vfid, tlv);
+}
+
+void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                               enum channel_tlvs expected_tlv)
+{
+       WARN(expected_tlv != vf->op_current,
+            "lock mismatch: expected %d found %d", expected_tlv,
+            vf->op_current);
+
+       /* lock the channel */
+       mutex_unlock(&vf->op_mutex);
+
+       /* log the unlock */
+       DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
+          vf->abs_vfid, vf->op_current);
+
+       /* record the locking op */
+       vf->op_current = CHANNEL_TLV_NONE;
+}
+
+void bnx2x_enable_sriov(struct bnx2x *bp)
+{
+       int rc = 0;
+
+       /* disbale sriov in case it is still enabled */
+       pci_disable_sriov(bp->pdev);
+       DP(BNX2X_MSG_IOV, "sriov disabled\n");
+
+       /* enable sriov */
+       DP(BNX2X_MSG_IOV, "vf num (%d)\n", (bp->vfdb->sriov.nr_virtfn));
+       rc = pci_enable_sriov(bp->pdev, (bp->vfdb->sriov.nr_virtfn));
+       if (rc)
+               BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
+       else
+               DP(BNX2X_MSG_IOV, "sriov enabled\n");
+}
+
+/* New mac for VF. Consider these cases:
+ * 1. VF hasn't been acquired yet - save the mac in local bulletin board and
+ *    supply at acquire.
+ * 2. VF has already been acquired but has not yet initialized - store in local
+ *    bulletin board. mac will be posted on VF bulletin board after VF init. VF
+ *    will configure this mac when it is ready.
+ * 3. VF has already initialized but has not yet setup a queue - post the new
+ *    mac on VF's bulletin board right now. VF will configure this mac when it
+ *    is ready.
+ * 4. VF has already set a queue - delete any macs already configured for this
+ *    queue and manually config the new mac.
+ * In any event, once this function has been called refuse any attempts by the
+ * VF to configure any mac for itself except for this mac. In case of a race
+ * where the VF fails to see the new post on its bulletin board before sending a
+ * mac configuration request, the PF will simply fail the request and VF can try
+ * again after consulting its bulletin board
+ */
+int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       int rc, q_logical_state, vfidx = queue;
+       struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+       struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+       /* if SRIOV is disabled there is nothing to do (and somewhere, someone
+        * has erred).
+        */
+       if (!IS_SRIOV(bp)) {
+               BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
+               return -EINVAL;
+       }
+
+       if (!is_valid_ether_addr(mac)) {
+               BNX2X_ERR("mac address invalid\n");
+               return -EINVAL;
+       }
+
+       /* update PF's copy of the VF's bulletin. will no longer accept mac
+        * configuration requests from vf unless match this mac
+        */
+       bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
+       memcpy(bulletin->mac, mac, ETH_ALEN);
+
+       /* Post update on VF's bulletin board */
+       rc = bnx2x_post_vf_bulletin(bp, vfidx);
+       if (rc) {
+               BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
+               return rc;
+       }
+
+       /* is vf initialized and queue set up? */
+       q_logical_state =
+               bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
+       if (vf->state == VF_ENABLED &&
+           q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+               /* configure the mac in device on this vf's queue */
+               unsigned long flags = 0;
+               struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+
+               /* must lock vfpf channel to protect against vf flows */
+               bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+
+               /* remove existing eth macs */
+               rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
+               if (rc) {
+                       BNX2X_ERR("failed to delete eth macs\n");
+                       return -EINVAL;
+               }
+
+               /* remove existing uc list macs */
+               rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
+               if (rc) {
+                       BNX2X_ERR("failed to delete uc_list macs\n");
+                       return -EINVAL;
+               }
+
+               /* configure the new mac to device */
+               __set_bit(RAMROD_COMP_WAIT, &flags);
+               bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
+                                 BNX2X_ETH_MAC, &flags);
+
+               bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+       }
+
+       return rc;
+}
+
+/* crc is the first field in the bulletin board. compute the crc over the
+ * entire bulletin board excluding the crc field itself
+ */
+u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
+                         struct pf_vf_bulletin_content *bulletin)
+{
+       return crc32(BULLETIN_CRC_SEED,
+                ((u8 *)bulletin) + sizeof(bulletin->crc),
+                bulletin->length - sizeof(bulletin->crc));
+}
+
+/* Check for new posts on the bulletin board */
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+       struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
+       int attempts;
+
+       /* bulletin board hasn't changed since last sample */
+       if (bp->old_bulletin.version == bulletin.version)
+               return PFVF_BULLETIN_UNCHANGED;
+
+       /* validate crc of new bulletin board */
+       if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
+               /* sampling structure in mid post may result with corrupted data
+                * validate crc to ensure coherency.
+                */
+               for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
+                       bulletin = bp->pf2vf_bulletin->content;
+                       if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
+                                                                 &bulletin))
+                               break;
+                       BNX2X_ERR("bad crc on bulletin board. contained %x computed %x\n",
+                                 bulletin.crc,
+                                 bnx2x_crc_vf_bulletin(bp, &bulletin));
+               }
+               if (attempts >= BULLETIN_ATTEMPTS) {
+                       BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
+                                 attempts);
+                       return PFVF_BULLETIN_CRC_ERR;
+               }
+       }
+
+       /* the mac address in bulletin board is valid and is new */
+       if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID &&
+           memcmp(bulletin.mac, bp->old_bulletin.mac, ETH_ALEN)) {
+               /* update new mac to net device */
+               memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
+       }
+
+       /* copy new bulletin board to bp */
+       bp->old_bulletin = bulletin;
+
+       return PFVF_BULLETIN_UPDATED;
+}
+
+void bnx2x_vf_map_doorbells(struct bnx2x *bp)
+{
+       /* vf doorbells are embedded within the regview */
+       bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START;
+}
+
+int bnx2x_vf_pci_alloc(struct bnx2x *bp)
+{
+       /* allocate vf2pf mailbox for vf to pf channel */
+       BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
+                       sizeof(struct bnx2x_vf_mbx_msg));
+
+       /* allocate pf 2 vf bulletin board */
+       BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
+                       sizeof(union pf_vf_bulletin));
+
+       return 0;
+
+alloc_mem_err:
+       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+                      sizeof(struct bnx2x_vf_mbx_msg));
+       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+                      sizeof(union pf_vf_bulletin));
+       return -ENOMEM;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
new file mode 100644 (file)
index 0000000..b405017
--- /dev/null
@@ -0,0 +1,809 @@
+/* bnx2x_sriov.h: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ *            Ariel Elior <ariele@broadcom.com>
+ */
+#ifndef BNX2X_SRIOV_H
+#define BNX2X_SRIOV_H
+
+#include "bnx2x_vfpf.h"
+#include "bnx2x.h"
+
+enum sample_bulletin_result {
+          PFVF_BULLETIN_UNCHANGED,
+          PFVF_BULLETIN_UPDATED,
+          PFVF_BULLETIN_CRC_ERR
+};
+
+#ifdef CONFIG_BNX2X_SRIOV
+
+/* The bnx2x device structure holds vfdb structure described below.
+ * The VF array is indexed by the relative vfid.
+ */
+#define BNX2X_VF_MAX_QUEUES            16
+#define BNX2X_VF_MAX_TPA_AGG_QUEUES    8
+
+struct bnx2x_sriov {
+       u32 first_vf_in_pf;
+
+       /* standard SRIOV capability fields, mostly for debugging */
+       int pos;                /* capability position */
+       int nres;               /* number of resources */
+       u32 cap;                /* SR-IOV Capabilities */
+       u16 ctrl;               /* SR-IOV Control */
+       u16 total;              /* total VFs associated with the PF */
+       u16 initial;            /* initial VFs associated with the PF */
+       u16 nr_virtfn;          /* number of VFs available */
+       u16 offset;             /* first VF Routing ID offset */
+       u16 stride;             /* following VF stride */
+       u32 pgsz;               /* page size for BAR alignment */
+       u8 link;                /* Function Dependency Link */
+};
+
+/* bars */
+struct bnx2x_vf_bar {
+       u64 bar;
+       u32 size;
+};
+
+struct bnx2x_vf_bar_info {
+       struct bnx2x_vf_bar bars[PCI_SRIOV_NUM_BARS];
+       u8 nr_bars;
+};
+
+/* vf queue (used both for rx or tx) */
+struct bnx2x_vf_queue {
+       struct eth_context              *cxt;
+
+       /* MACs object */
+       struct bnx2x_vlan_mac_obj       mac_obj;
+
+       /* VLANs object */
+       struct bnx2x_vlan_mac_obj       vlan_obj;
+       atomic_t vlan_count;            /* 0 means vlan-0 is set  ~ untagged */
+
+       /* Queue Slow-path State object */
+       struct bnx2x_queue_sp_obj       sp_obj;
+
+       u32 cid;
+       u16 index;
+       u16 sb_idx;
+};
+
+/* struct bnx2x_vfop_qctor_params - prepare queue construction parameters:
+ * q-init, q-setup and SB index
+ */
+struct bnx2x_vfop_qctor_params {
+       struct bnx2x_queue_state_params         qstate;
+       struct bnx2x_queue_setup_params         prep_qsetup;
+};
+
+/* VFOP parameters (one copy per VF) */
+union bnx2x_vfop_params {
+       struct bnx2x_vlan_mac_ramrod_params     vlan_mac;
+       struct bnx2x_rx_mode_ramrod_params      rx_mode;
+       struct bnx2x_mcast_ramrod_params        mcast;
+       struct bnx2x_config_rss_params          rss;
+       struct bnx2x_vfop_qctor_params          qctor;
+};
+
+/* forward */
+struct bnx2x_virtf;
+
+/* VFOP definitions */
+typedef void (*vfop_handler_t)(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+struct bnx2x_vfop_cmd {
+       vfop_handler_t done;
+       bool block;
+};
+
+/* VFOP queue filters command additional arguments */
+struct bnx2x_vfop_filter {
+       struct list_head link;
+       int type;
+#define BNX2X_VFOP_FILTER_MAC  1
+#define BNX2X_VFOP_FILTER_VLAN 2
+
+       bool add;
+       u8 *mac;
+       u16 vid;
+};
+
+struct bnx2x_vfop_filters {
+       int add_cnt;
+       struct list_head head;
+       struct bnx2x_vfop_filter filters[];
+};
+
+/* transient list allocated, built and saved until its
+ * passed to the SP-VERBs layer.
+ */
+struct bnx2x_vfop_args_mcast {
+       int mc_num;
+       struct bnx2x_mcast_list_elem *mc;
+};
+
+struct bnx2x_vfop_args_qctor {
+       int     qid;
+       u16     sb_idx;
+};
+
+struct bnx2x_vfop_args_qdtor {
+       int     qid;
+       struct eth_context *cxt;
+};
+
+struct bnx2x_vfop_args_defvlan {
+       int     qid;
+       bool    enable;
+       u16     vid;
+       u8      prio;
+};
+
+struct bnx2x_vfop_args_qx {
+       int     qid;
+       bool    en_add;
+};
+
+struct bnx2x_vfop_args_filters {
+       struct bnx2x_vfop_filters *multi_filter;
+       atomic_t *credit;       /* non NULL means 'don't consume credit' */
+};
+
+union bnx2x_vfop_args {
+       struct bnx2x_vfop_args_mcast    mc_list;
+       struct bnx2x_vfop_args_qctor    qctor;
+       struct bnx2x_vfop_args_qdtor    qdtor;
+       struct bnx2x_vfop_args_defvlan  defvlan;
+       struct bnx2x_vfop_args_qx       qx;
+       struct bnx2x_vfop_args_filters  filters;
+};
+
+struct bnx2x_vfop {
+       struct list_head link;
+       int                     rc;             /* return code */
+       int                     state;          /* next state */
+       union bnx2x_vfop_args   args;           /* extra arguments */
+       union bnx2x_vfop_params *op_p;          /* ramrod params */
+
+       /* state machine callbacks */
+       vfop_handler_t transition;
+       vfop_handler_t done;
+};
+
+/* vf context */
+struct bnx2x_virtf {
+       u16 cfg_flags;
+#define VF_CFG_STATS           0x0001
+#define VF_CFG_FW_FC           0x0002
+#define VF_CFG_TPA             0x0004
+#define VF_CFG_INT_SIMD                0x0008
+#define VF_CACHE_LINE          0x0010
+
+       u8 state;
+#define VF_FREE                0       /* VF ready to be acquired holds no resc */
+#define VF_ACQUIRED    1       /* VF aquired, but not initalized */
+#define VF_ENABLED     2       /* VF Enabled */
+#define VF_RESET       3       /* VF FLR'd, pending cleanup */
+
+       /* non 0 during flr cleanup */
+       u8 flr_clnup_stage;
+#define VF_FLR_CLN     1       /* reclaim resources and do 'final cleanup'
+                                * sans the end-wait
+                                */
+#define VF_FLR_ACK     2       /* ACK flr notification */
+#define VF_FLR_EPILOG  3       /* wait for VF remnants to dissipate in the HW
+                                * ~ final cleanup' end wait
+                                */
+
+       /* dma */
+       dma_addr_t fw_stat_map;         /* valid iff VF_CFG_STATS */
+       dma_addr_t spq_map;
+       dma_addr_t bulletin_map;
+
+       /* Allocated resources counters. Before the VF is acquired, the
+        * counters hold the following values:
+        *
+        * - xxq_count = 0 as the queues memory is not allocated yet.
+        *
+        * - sb_count  = The number of status blocks configured for this VF in
+        *               the IGU CAM. Initially read during probe.
+        *
+        * - xx_rules_count = The number of rules statically and equally
+        *                    allocated for each VF, during PF load.
+        */
+       struct vf_pf_resc_request       alloc_resc;
+#define vf_rxq_count(vf)               ((vf)->alloc_resc.num_rxqs)
+#define vf_txq_count(vf)               ((vf)->alloc_resc.num_txqs)
+#define vf_sb_count(vf)                        ((vf)->alloc_resc.num_sbs)
+#define vf_mac_rules_cnt(vf)           ((vf)->alloc_resc.num_mac_filters)
+#define vf_vlan_rules_cnt(vf)          ((vf)->alloc_resc.num_vlan_filters)
+#define vf_mc_rules_cnt(vf)            ((vf)->alloc_resc.num_mc_filters)
+
+       u8 sb_count;    /* actual number of SBs */
+       u8 igu_base_id; /* base igu status block id */
+
+       struct bnx2x_vf_queue   *vfqs;
+#define bnx2x_vfq(vf, nr, var) ((vf)->vfqs[(nr)].var)
+
+       u8 index;       /* index in the vf array */
+       u8 abs_vfid;
+       u8 sp_cl_id;
+       u32 error;      /* 0 means all's-well */
+
+       /* BDF */
+       unsigned int bus;
+       unsigned int devfn;
+
+       /* bars */
+       struct bnx2x_vf_bar bars[PCI_SRIOV_NUM_BARS];
+
+       /* set-mac ramrod state 1-pending, 0-done */
+       unsigned long   filter_state;
+
+       /* leading rss client id ~~ the client id of the first rxq, must be
+        * set for each txq.
+        */
+       int leading_rss;
+
+       /* MCAST object */
+       struct bnx2x_mcast_obj          mcast_obj;
+
+       /* RSS configuration object */
+       struct bnx2x_rss_config_obj     rss_conf_obj;
+
+       /* slow-path operations */
+       atomic_t                        op_in_progress;
+       int                             op_rc;
+       bool                            op_wait_blocking;
+       struct list_head                op_list_head;
+       union bnx2x_vfop_params         op_params;
+       struct mutex                    op_mutex; /* one vfop at a time mutex */
+       enum channel_tlvs               op_current;
+};
+
+#define BNX2X_NR_VIRTFN(bp)    ((bp)->vfdb->sriov.nr_virtfn)
+
+#define for_each_vf(bp, var) \
+               for ((var) = 0; (var) < BNX2X_NR_VIRTFN(bp); (var)++)
+
+#define for_each_vfq(vf, var) \
+               for ((var) = 0; (var) < vf_rxq_count(vf); (var)++)
+
+#define for_each_vf_sb(vf, var) \
+               for ((var) = 0; (var) < vf_sb_count(vf); (var)++)
+
+#define is_vf_multi(vf)        (vf_rxq_count(vf) > 1)
+
+#define HW_VF_HANDLE(bp, abs_vfid) \
+       (u16)(BP_ABS_FUNC((bp)) | (1<<3) |  ((u16)(abs_vfid) << 4))
+
+#define FW_PF_MAX_HANDLE       8
+
+#define FW_VF_HANDLE(abs_vfid) \
+       (abs_vfid + FW_PF_MAX_HANDLE)
+
+/* locking and unlocking the channel mutex */
+void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                             enum channel_tlvs tlv);
+
+void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                               enum channel_tlvs expected_tlv);
+
+/* VF mail box (aka vf-pf channel) */
+
+/* a container for the bi-directional vf<-->pf messages.
+ *  The actual response will be placed according to the offset parameter
+ *  provided in the request
+ */
+
+#define MBX_MSG_ALIGN  8
+#define MBX_MSG_ALIGNED_SIZE   (roundup(sizeof(struct bnx2x_vf_mbx_msg), \
+                               MBX_MSG_ALIGN))
+
+struct bnx2x_vf_mbx_msg {
+       union vfpf_tlvs req;
+       union pfvf_tlvs resp;
+};
+
+struct bnx2x_vf_mbx {
+       struct bnx2x_vf_mbx_msg *msg;
+       dma_addr_t msg_mapping;
+
+       /* VF GPA address */
+       u32 vf_addr_lo;
+       u32 vf_addr_hi;
+
+       struct vfpf_first_tlv first_tlv;        /* saved VF request header */
+
+       u8 flags;
+#define VF_MSG_INPROCESS       0x1     /* failsafe - the FW should prevent
+                                        * more then one pending msg
+                                        */
+};
+
+struct bnx2x_vf_sp {
+       union {
+               struct eth_classify_rules_ramrod_data   e2;
+       } mac_rdata;
+
+       union {
+               struct eth_classify_rules_ramrod_data   e2;
+       } vlan_rdata;
+
+       union {
+               struct eth_filter_rules_ramrod_data     e2;
+       } rx_mode_rdata;
+
+       union {
+               struct eth_multicast_rules_ramrod_data  e2;
+       } mcast_rdata;
+
+       union {
+               struct client_init_ramrod_data  init_data;
+               struct client_update_ramrod_data update_data;
+       } q_data;
+};
+
+struct hw_dma {
+       void *addr;
+       dma_addr_t mapping;
+       size_t size;
+};
+
+struct bnx2x_vfdb {
+#define BP_VFDB(bp)            ((bp)->vfdb)
+       /* vf array */
+       struct bnx2x_virtf      *vfs;
+#define BP_VF(bp, idx)         (&((bp)->vfdb->vfs[(idx)]))
+#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[(idx)].var)
+
+       /* queue array - for all vfs */
+       struct bnx2x_vf_queue *vfqs;
+
+       /* vf HW contexts */
+       struct hw_dma           context[BNX2X_VF_CIDS/ILT_PAGE_CIDS];
+#define        BP_VF_CXT_PAGE(bp, i)   (&(bp)->vfdb->context[(i)])
+
+       /* SR-IOV information */
+       struct bnx2x_sriov      sriov;
+       struct hw_dma           mbx_dma;
+#define BP_VF_MBX_DMA(bp)      (&((bp)->vfdb->mbx_dma))
+       struct bnx2x_vf_mbx     mbxs[BNX2X_MAX_NUM_OF_VFS];
+#define BP_VF_MBX(bp, vfid)    (&((bp)->vfdb->mbxs[(vfid)]))
+
+       struct hw_dma           bulletin_dma;
+#define BP_VF_BULLETIN_DMA(bp) (&((bp)->vfdb->bulletin_dma))
+#define        BP_VF_BULLETIN(bp, vf) \
+       (((struct pf_vf_bulletin_content *)(BP_VF_BULLETIN_DMA(bp)->addr)) \
+        + (vf))
+
+       struct hw_dma           sp_dma;
+#define bnx2x_vf_sp(bp, vf, field) ((bp)->vfdb->sp_dma.addr +          \
+               (vf)->index * sizeof(struct bnx2x_vf_sp) +              \
+               offsetof(struct bnx2x_vf_sp, field))
+#define bnx2x_vf_sp_map(bp, vf, field) ((bp)->vfdb->sp_dma.mapping +   \
+               (vf)->index * sizeof(struct bnx2x_vf_sp) +              \
+               offsetof(struct bnx2x_vf_sp, field))
+
+#define FLRD_VFS_DWORDS (BNX2X_MAX_NUM_OF_VFS / 32)
+       u32 flrd_vfs[FLRD_VFS_DWORDS];
+};
+
+/* queue access */
+static inline struct bnx2x_vf_queue *vfq_get(struct bnx2x_virtf *vf, u8 index)
+{
+       return &(vf->vfqs[index]);
+}
+
+static inline bool vfq_is_leading(struct bnx2x_vf_queue *vfq)
+{
+       return (vfq->index == 0);
+}
+
+/* FW ids */
+static inline u8 vf_igu_sb(struct bnx2x_virtf *vf, u16 sb_idx)
+{
+       return vf->igu_base_id + sb_idx;
+}
+
+static inline u8 vf_hc_qzone(struct bnx2x_virtf *vf, u16 sb_idx)
+{
+       return vf_igu_sb(vf, sb_idx);
+}
+
+static u8 vfq_cl_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+       return vf->igu_base_id + q->index;
+}
+
+static inline u8 vfq_stat_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+       return vfq_cl_id(vf, q);
+}
+
+static inline u8 vfq_qzone_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+       return vfq_cl_id(vf, q);
+}
+
+/* global iov routines */
+int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line);
+int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, int num_vfs_param);
+void bnx2x_iov_remove_one(struct bnx2x *bp);
+void bnx2x_iov_free_mem(struct bnx2x *bp);
+int bnx2x_iov_alloc_mem(struct bnx2x *bp);
+int bnx2x_iov_nic_init(struct bnx2x *bp);
+int bnx2x_iov_chip_cleanup(struct bnx2x *bp);
+void bnx2x_iov_init_dq(struct bnx2x *bp);
+void bnx2x_iov_init_dmae(struct bnx2x *bp);
+void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+                               struct bnx2x_queue_sp_obj **q_obj);
+void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work);
+int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem);
+void bnx2x_iov_adjust_stats_req(struct bnx2x *bp);
+void bnx2x_iov_storm_stats_update(struct bnx2x *bp);
+void bnx2x_iov_sp_task(struct bnx2x *bp);
+/* global vf mailbox routines */
+void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
+void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
+
+/* CORE VF API */
+typedef u8 bnx2x_mac_addr_t[ETH_ALEN];
+
+/* acquire */
+int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                    struct vf_pf_resc_request *resc);
+/* init */
+int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                 dma_addr_t *sb_map);
+
+/* VFOP generic helpers */
+#define bnx2x_vfop_default(state) do {                         \
+               BNX2X_ERR("Bad state %d\n", (state));           \
+               vfop->rc = -EINVAL;                             \
+               goto op_err;                                    \
+       } while (0)
+
+enum {
+       VFOP_DONE,
+       VFOP_CONT,
+       VFOP_VERIFY_PEND,
+};
+
+#define bnx2x_vfop_finalize(vf, rc, next) do {                         \
+               if ((rc) < 0)                                           \
+                       goto op_err;                                    \
+               else if ((rc) > 0)                                      \
+                       goto op_pending;                                \
+               else if ((next) == VFOP_DONE)                           \
+                       goto op_done;                                   \
+               else if ((next) == VFOP_VERIFY_PEND)                    \
+                       BNX2X_ERR("expected pending\n");                \
+               else {                                                  \
+                       DP(BNX2X_MSG_IOV, "no ramrod. scheduling\n");   \
+                       atomic_set(&vf->op_in_progress, 1);             \
+                       queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);  \
+                       return;                                         \
+               }                                                       \
+       } while (0)
+
+#define bnx2x_vfop_opset(first_state, trans_hndlr, done_hndlr)         \
+       do {                                                            \
+               vfop->state = first_state;                              \
+               vfop->op_p = &vf->op_params;                            \
+               vfop->transition = trans_hndlr;                         \
+               vfop->done = done_hndlr;                                \
+       } while (0)
+
+static inline struct bnx2x_vfop *bnx2x_vfop_cur(struct bnx2x *bp,
+                                               struct bnx2x_virtf *vf)
+{
+       WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
+       WARN_ON(list_empty(&vf->op_list_head));
+       return list_first_entry(&vf->op_list_head, struct bnx2x_vfop, link);
+}
+
+static inline struct bnx2x_vfop *bnx2x_vfop_add(struct bnx2x *bp,
+                                               struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = kzalloc(sizeof(*vfop), GFP_KERNEL);
+
+       WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
+       if (vfop) {
+               INIT_LIST_HEAD(&vfop->link);
+               list_add(&vfop->link, &vf->op_list_head);
+       }
+       return vfop;
+}
+
+static inline void bnx2x_vfop_end(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                 struct bnx2x_vfop *vfop)
+{
+       /* rc < 0 - error, otherwise set to 0 */
+       DP(BNX2X_MSG_IOV, "rc was %d\n", vfop->rc);
+       if (vfop->rc >= 0)
+               vfop->rc = 0;
+       DP(BNX2X_MSG_IOV, "rc is now %d\n", vfop->rc);
+
+       /* unlink the current op context and propagate error code
+        * must be done before invoking the 'done()' handler
+        */
+       WARN(!mutex_is_locked(&vf->op_mutex),
+            "about to access vf op linked list but mutex was not locked!");
+       list_del(&vfop->link);
+
+       if (list_empty(&vf->op_list_head)) {
+               DP(BNX2X_MSG_IOV, "list was empty %d\n", vfop->rc);
+               vf->op_rc = vfop->rc;
+               DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d,  vfop->rc %d\n",
+                  vf->op_rc, vfop->rc);
+       } else {
+               struct bnx2x_vfop *cur_vfop;
+
+               DP(BNX2X_MSG_IOV, "list not empty %d\n", vfop->rc);
+               cur_vfop = bnx2x_vfop_cur(bp, vf);
+               cur_vfop->rc = vfop->rc;
+               DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d, vfop->rc %d\n",
+                  vf->op_rc, vfop->rc);
+       }
+
+       /* invoke done handler */
+       if (vfop->done) {
+               DP(BNX2X_MSG_IOV, "calling done handler\n");
+               vfop->done(bp, vf);
+       } else {
+               /* there is no done handler for the operation to unlock
+                * the mutex. Must have gotten here from PF initiated VF RELEASE
+                */
+               bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+       }
+
+       DP(BNX2X_MSG_IOV, "done handler complete. vf->op_rc %d, vfop->rc %d\n",
+          vf->op_rc, vfop->rc);
+
+       /* if this is the last nested op reset the wait_blocking flag
+        * to release any blocking wrappers, only after 'done()' is invoked
+        */
+       if (list_empty(&vf->op_list_head)) {
+               DP(BNX2X_MSG_IOV, "list was empty after done %d\n", vfop->rc);
+               vf->op_wait_blocking = false;
+       }
+
+       kfree(vfop);
+}
+
+static inline int bnx2x_vfop_wait_blocking(struct bnx2x *bp,
+                                          struct bnx2x_virtf *vf)
+{
+       /* can take a while if any port is running */
+       int cnt = 5000;
+
+       might_sleep();
+       while (cnt--) {
+               if (vf->op_wait_blocking == false) {
+#ifdef BNX2X_STOP_ON_ERROR
+                       DP(BNX2X_MSG_IOV, "exit  (cnt %d)\n", 5000 - cnt);
+#endif
+                       return 0;
+               }
+               usleep_range(1000, 2000);
+
+               if (bp->panic)
+                       return -EIO;
+       }
+
+       /* timeout! */
+#ifdef BNX2X_STOP_ON_ERROR
+       bnx2x_panic();
+#endif
+
+       return -EBUSY;
+}
+
+static inline int bnx2x_vfop_transition(struct bnx2x *bp,
+                                       struct bnx2x_virtf *vf,
+                                       vfop_handler_t transition,
+                                       bool block)
+{
+       if (block)
+               vf->op_wait_blocking = true;
+       transition(bp, vf);
+       if (block)
+               return bnx2x_vfop_wait_blocking(bp, vf);
+       return 0;
+}
+
+/* VFOP queue construction helpers */
+void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                           struct bnx2x_queue_init_params *init_params,
+                           struct bnx2x_queue_setup_params *setup_params,
+                           u16 q_idx, u16 sb_idx);
+
+void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                           struct bnx2x_queue_init_params *init_params,
+                           struct bnx2x_queue_setup_params *setup_params,
+                           u16 q_idx, u16 sb_idx);
+
+void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
+                          struct bnx2x_virtf *vf,
+                          struct bnx2x_vf_queue *q,
+                          struct bnx2x_vfop_qctor_params *p,
+                          unsigned long q_type);
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+                           struct bnx2x_virtf *vf,
+                           struct bnx2x_vfop_cmd *cmd,
+                           struct bnx2x_vfop_filters *macs,
+                           int qid, bool drv_only);
+
+int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+                           struct bnx2x_virtf *vf,
+                           struct bnx2x_vfop_cmd *cmd,
+                           int qid, u16 vid, bool add);
+
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+                            struct bnx2x_virtf *vf,
+                            struct bnx2x_vfop_cmd *cmd,
+                            struct bnx2x_vfop_filters *vlans,
+                            int qid, bool drv_only);
+
+int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
+                         struct bnx2x_virtf *vf,
+                         struct bnx2x_vfop_cmd *cmd,
+                         int qid);
+
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd,
+                        int qid);
+
+int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd,
+                        bnx2x_mac_addr_t *mcasts,
+                        int mcast_num, bool drv_only);
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+                         struct bnx2x_virtf *vf,
+                         struct bnx2x_vfop_cmd *cmd,
+                         int qid, unsigned long accept_flags);
+
+int bnx2x_vfop_close_cmd(struct bnx2x *bp,
+                        struct bnx2x_virtf *vf,
+                        struct bnx2x_vfop_cmd *cmd);
+
+int bnx2x_vfop_release_cmd(struct bnx2x *bp,
+                          struct bnx2x_virtf *vf,
+                          struct bnx2x_vfop_cmd *cmd);
+
+/* VF release ~ VF close + VF release-resources
+ *
+ * Release is the ultimate SW shutdown and is called whenever an
+ * irrecoverable error is encountered.
+ */
+void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block);
+int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
+u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+/* FLR routines */
+
+/* VF FLR helpers */
+int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid);
+void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid);
+
+/* Handles an FLR (or VF_DISABLE) notification form the MCP */
+void bnx2x_vf_handle_flr_event(struct bnx2x *bp);
+
+void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
+                  u16 length);
+void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
+                    u16 type, u16 length);
+void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);
+
+bool bnx2x_tlv_supported(u16 tlvtype);
+
+u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
+                         struct pf_vf_bulletin_content *bulletin);
+int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);
+
+
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+
+/* VF side vfpf channel functions */
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_init(struct bnx2x *bp);
+void bnx2x_vfpf_close_vf(struct bnx2x *bp);
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx);
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
+int bnx2x_vfpf_set_mac(struct bnx2x *bp);
+int bnx2x_vfpf_set_mcast(struct net_device *dev);
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp);
+
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+                                       size_t buf_len)
+{
+       strlcpy(buf, bp->acquire_resp.pfdev_info.fw_ver, buf_len);
+}
+
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+                                              struct bnx2x_fastpath *fp)
+{
+       return PXP_VF_ADDR_USDM_QUEUES_START +
+               bp->acquire_resp.resc.hw_qid[fp->index] *
+               sizeof(struct ustorm_queue_zone_data);
+}
+
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+void bnx2x_vf_map_doorbells(struct bnx2x *bp);
+int bnx2x_vf_pci_alloc(struct bnx2x *bp);
+void bnx2x_enable_sriov(struct bnx2x *bp);
+static inline int bnx2x_vf_headroom(struct bnx2x *bp)
+{
+       return bp->vfdb->sriov.nr_virtfn * BNX2X_CLIENTS_PER_VF;
+}
+
+#else /* CONFIG_BNX2X_SRIOV */
+
+static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+                               struct bnx2x_queue_sp_obj **q_obj) {}
+static inline void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid,
+                                     bool queue_work) {}
+static inline void bnx2x_vf_handle_flr_event(struct bnx2x *bp) {}
+static inline int bnx2x_iov_eq_sp_event(struct bnx2x *bp,
+                                       union event_ring_elem *elem) {return 1; }
+static inline void bnx2x_iov_sp_task(struct bnx2x *bp) {}
+static inline void bnx2x_vf_mbx(struct bnx2x *bp,
+                               struct vf_pf_event_data *vfpf_event) {}
+static inline int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line) {return line; }
+static inline void bnx2x_iov_init_dq(struct bnx2x *bp) {}
+static inline int bnx2x_iov_alloc_mem(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_free_mem(struct bnx2x *bp) {}
+static inline int bnx2x_iov_chip_cleanup(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_init_dmae(struct bnx2x *bp) {}
+static inline int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
+                                    int num_vfs_param) {return 0; }
+static inline void bnx2x_iov_remove_one(struct bnx2x *bp) {}
+static inline void bnx2x_enable_sriov(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_acquire(struct bnx2x *bp,
+                                    u8 tx_count, u8 rx_count) {return 0; }
+static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) {return 0; }
+static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; }
+static inline int bnx2x_vfpf_set_mac(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_set_mcast(struct net_device *dev) {return 0; }
+static inline int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_iov_nic_init(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_headroom(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_adjust_stats_req(struct bnx2x *bp) {}
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+                                       size_t buf_len) {}
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+                                              struct bnx2x_fastpath *fp) {return 0; }
+static inline enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+       return PFVF_BULLETIN_UNCHANGED;
+}
+
+static inline int bnx2x_vf_map_doorbells(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; }
+
+#endif /* CONFIG_BNX2X_SRIOV */
+#endif /* bnx2x_sriov.h */
index 89ec0667140a02dc67f16b2ae79a59eaeaccff5e..4397f8b76f2ea79e23bbe730329e488ded73f749 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_stats.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
 
 #include "bnx2x_stats.h"
 #include "bnx2x_cmn.h"
-
+#include "bnx2x_sriov.h"
 
 /* Statistics */
 
@@ -79,6 +79,42 @@ static inline u16 bnx2x_get_port_stats_dma_len(struct bnx2x *bp)
  * Init service functions
  */
 
+static void bnx2x_dp_stats(struct bnx2x *bp)
+{
+       int i;
+
+       DP(BNX2X_MSG_STATS, "dumping stats:\n"
+          "fw_stats_req\n"
+          "    hdr\n"
+          "        cmd_num %d\n"
+          "        reserved0 %d\n"
+          "        drv_stats_counter %d\n"
+          "        reserved1 %d\n"
+          "        stats_counters_addrs %x %x\n",
+          bp->fw_stats_req->hdr.cmd_num,
+          bp->fw_stats_req->hdr.reserved0,
+          bp->fw_stats_req->hdr.drv_stats_counter,
+          bp->fw_stats_req->hdr.reserved1,
+          bp->fw_stats_req->hdr.stats_counters_addrs.hi,
+          bp->fw_stats_req->hdr.stats_counters_addrs.lo);
+
+       for (i = 0; i < bp->fw_stats_req->hdr.cmd_num; i++) {
+               DP(BNX2X_MSG_STATS,
+                  "query[%d]\n"
+                  "              kind %d\n"
+                  "              index %d\n"
+                  "              funcID %d\n"
+                  "              reserved %d\n"
+                  "              address %x %x\n",
+                  i, bp->fw_stats_req->query[i].kind,
+                  bp->fw_stats_req->query[i].index,
+                  bp->fw_stats_req->query[i].funcID,
+                  bp->fw_stats_req->query[i].reserved,
+                  bp->fw_stats_req->query[i].address.hi,
+                  bp->fw_stats_req->query[i].address.lo);
+       }
+}
+
 /* Post the next statistics ramrod. Protect it with the spin in
  * order to ensure the strict order between statistics ramrods
  * (each ramrod has a sequence number passed in a
@@ -103,7 +139,9 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
                DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
                        bp->fw_stats_req->hdr.drv_stats_counter);
 
-
+               /* adjust the ramrod to include VF queues statistics */
+               bnx2x_iov_adjust_stats_req(bp);
+               bnx2x_dp_stats(bp);
 
                /* send FW stats ramrod */
                rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
@@ -174,7 +212,7 @@ static int bnx2x_stats_comp(struct bnx2x *bp)
                        break;
                }
                cnt--;
-               usleep_range(1000, 1000);
+               usleep_range(1000, 2000);
        }
        return 1;
 }
@@ -482,6 +520,12 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
 
 static void bnx2x_stats_start(struct bnx2x *bp)
 {
+       /* vfs travel through here as part of the statistics FSM, but no action
+        * is required
+        */
+       if (IS_VF(bp))
+               return;
+
        if (bp->port.pmf)
                bnx2x_port_stats_init(bp);
 
@@ -501,6 +545,11 @@ static void bnx2x_stats_pmf_start(struct bnx2x *bp)
 
 static void bnx2x_stats_restart(struct bnx2x *bp)
 {
+       /* vfs travel through here as part of the statistics FSM, but no action
+        * is required
+        */
+       if (IS_VF(bp))
+               return;
        bnx2x_stats_comp(bp);
        bnx2x_stats_start(bp);
 }
@@ -832,19 +881,10 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
        return 0;
 }
 
-static int bnx2x_storm_stats_update(struct bnx2x *bp)
+static int bnx2x_storm_stats_validate_counters(struct bnx2x *bp)
 {
-       struct tstorm_per_port_stats *tport =
-                               &bp->fw_stats_data->port.tstorm_port_statistics;
-       struct tstorm_per_pf_stats *tfunc =
-                               &bp->fw_stats_data->pf.tstorm_pf_statistics;
-       struct host_func_stats *fstats = &bp->func_stats;
-       struct bnx2x_eth_stats *estats = &bp->eth_stats;
-       struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old;
        struct stats_counter *counters = &bp->fw_stats_data->storm_counters;
-       int i;
        u16 cur_stats_counter;
-
        /* Make sure we use the value of the counter
         * used for sending the last stats ramrod.
         */
@@ -880,6 +920,23 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
                   le16_to_cpu(counters->tstats_counter), bp->stats_counter);
                return -EAGAIN;
        }
+       return 0;
+}
+
+static int bnx2x_storm_stats_update(struct bnx2x *bp)
+{
+       struct tstorm_per_port_stats *tport =
+                               &bp->fw_stats_data->port.tstorm_port_statistics;
+       struct tstorm_per_pf_stats *tfunc =
+                               &bp->fw_stats_data->pf.tstorm_pf_statistics;
+       struct host_func_stats *fstats = &bp->func_stats;
+       struct bnx2x_eth_stats *estats = &bp->eth_stats;
+       struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old;
+       int i;
+
+       /* vfs stat counter is managed by pf */
+       if (IS_PF(bp) && bnx2x_storm_stats_validate_counters(bp))
+               return -EAGAIN;
 
        estats->error_bytes_received_hi = 0;
        estats->error_bytes_received_lo = 0;
@@ -953,8 +1010,8 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
                UPDATE_EXTEND_TSTAT(rcv_bcast_pkts,
                                        total_broadcast_packets_received);
                UPDATE_EXTEND_E_TSTAT(pkts_too_big_discard,
-                                     etherstatsoverrsizepkts);
-               UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard);
+                                     etherstatsoverrsizepkts, 32);
+               UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard, 16);
 
                SUB_EXTEND_USTAT(ucast_no_buff_pkts,
                                        total_unicast_packets_received);
@@ -1033,15 +1090,15 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
               estats->total_bytes_received_lo,
               estats->rx_stat_ifhcinbadoctets_lo);
 
-       ADD_64(estats->total_bytes_received_hi,
-              le32_to_cpu(tfunc->rcv_error_bytes.hi),
-              estats->total_bytes_received_lo,
-              le32_to_cpu(tfunc->rcv_error_bytes.lo));
+       ADD_64_LE(estats->total_bytes_received_hi,
+                 tfunc->rcv_error_bytes.hi,
+                 estats->total_bytes_received_lo,
+                 tfunc->rcv_error_bytes.lo);
 
-       ADD_64(estats->error_bytes_received_hi,
-              le32_to_cpu(tfunc->rcv_error_bytes.hi),
-              estats->error_bytes_received_lo,
-              le32_to_cpu(tfunc->rcv_error_bytes.lo));
+       ADD_64_LE(estats->error_bytes_received_hi,
+                 tfunc->rcv_error_bytes.hi,
+                 estats->error_bytes_received_lo,
+                 tfunc->rcv_error_bytes.lo);
 
        UPDATE_ESTAT(etherstatsoverrsizepkts, rx_stat_dot3statsframestoolong);
 
@@ -1174,23 +1231,34 @@ static void bnx2x_stats_update(struct bnx2x *bp)
        if (bnx2x_edebug_stats_stopped(bp))
                return;
 
-       if (*stats_comp != DMAE_COMP_VAL)
-               return;
+       if (IS_PF(bp)) {
+               if (*stats_comp != DMAE_COMP_VAL)
+                       return;
 
-       if (bp->port.pmf)
-               bnx2x_hw_stats_update(bp);
+               if (bp->port.pmf)
+                       bnx2x_hw_stats_update(bp);
 
-       if (bnx2x_storm_stats_update(bp)) {
-               if (bp->stats_pending++ == 3) {
-                       BNX2X_ERR("storm stats were not updated for 3 times\n");
-                       bnx2x_panic();
+               if (bnx2x_storm_stats_update(bp)) {
+                       if (bp->stats_pending++ == 3) {
+                               BNX2X_ERR("storm stats were not updated for 3 times\n");
+                               bnx2x_panic();
+                       }
+                       return;
                }
-               return;
+       } else {
+               /* vf doesn't collect HW statistics, and doesn't get completions
+                * perform only update
+                */
+               bnx2x_storm_stats_update(bp);
        }
 
        bnx2x_net_stats_update(bp);
        bnx2x_drv_stats_update(bp);
 
+       /* vf is done */
+       if (IS_VF(bp))
+               return;
+
        if (netif_msg_timer(bp)) {
                struct bnx2x_eth_stats *estats = &bp->eth_stats;
 
index b4d7b26c7fe78906be5998608c3b0d46b7e1df84..364e37ecbc5cc013573ab63f5e1125f1e8cd750e 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_stats.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -421,16 +421,19 @@ struct bnx2x_fw_port_stats_old {
                              new->s); \
        } while (0)
 
-#define UPDATE_EXTEND_TSTAT(s, t) \
+#define UPDATE_EXTEND_TSTAT_X(s, t, size) \
        do { \
-               diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \
+               diff = le##size##_to_cpu(tclient->s) - \
+                      le##size##_to_cpu(old_tclient->s); \
                old_tclient->s = tclient->s; \
                ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
        } while (0)
 
-#define UPDATE_EXTEND_E_TSTAT(s, t) \
+#define UPDATE_EXTEND_TSTAT(s, t) UPDATE_EXTEND_TSTAT_X(s, t, 32)
+
+#define UPDATE_EXTEND_E_TSTAT(s, t, size) \
        do { \
-               UPDATE_EXTEND_TSTAT(s, t); \
+               UPDATE_EXTEND_TSTAT_X(s, t, size); \
                ADD_EXTEND_64(estats->t##_hi, estats->t##_lo, diff); \
        } while (0)
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
new file mode 100644 (file)
index 0000000..3624612
--- /dev/null
@@ -0,0 +1,1651 @@
+/* bnx2x_vfpf.c: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ *            Ariel Elior <ariele@broadcom.com>
+ */
+
+#include "bnx2x.h"
+#include "bnx2x_cmn.h"
+#include <linux/crc32.h>
+
+/* place a given tlv on the tlv buffer at a given offset */
+void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
+                  u16 length)
+{
+       struct channel_tlv *tl =
+               (struct channel_tlv *)(tlvs_list + offset);
+
+       tl->type = type;
+       tl->length = length;
+}
+
+/* Clear the mailbox and init the header of the first tlv */
+void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
+                    u16 type, u16 length)
+{
+       DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n",
+          type);
+
+       /* Clear mailbox */
+       memset(bp->vf2pf_mbox, 0, sizeof(struct bnx2x_vf_mbx_msg));
+
+       /* init type and length */
+       bnx2x_add_tlv(bp, &first_tlv->tl, 0, type, length);
+
+       /* init first tlv header */
+       first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req);
+}
+
+/* list the types and lengths of the tlvs on the buffer */
+void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
+{
+       int i = 1;
+       struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;
+
+       while (tlv->type != CHANNEL_TLV_LIST_END) {
+               /* output tlv */
+               DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
+                  tlv->type, tlv->length);
+
+               /* advance to next tlv */
+               tlvs_list += tlv->length;
+
+               /* cast general tlv list pointer to channel tlv header*/
+               tlv = (struct channel_tlv *)tlvs_list;
+
+               i++;
+
+               /* break condition for this loop */
+               if (i > MAX_TLVS_IN_LIST) {
+                       WARN(true, "corrupt tlvs");
+                       return;
+               }
+       }
+
+       /* output last tlv */
+       DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
+          tlv->type, tlv->length);
+}
+
+/* test whether we support a tlv type */
+bool bnx2x_tlv_supported(u16 tlvtype)
+{
+       return CHANNEL_TLV_NONE < tlvtype && tlvtype < CHANNEL_TLV_MAX;
+}
+
+static inline int bnx2x_pfvf_status_codes(int rc)
+{
+       switch (rc) {
+       case 0:
+               return PFVF_STATUS_SUCCESS;
+       case -ENOMEM:
+               return PFVF_STATUS_NO_RESOURCE;
+       default:
+               return PFVF_STATUS_FAILURE;
+       }
+}
+
+int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping)
+{
+       struct cstorm_vf_zone_data __iomem *zone_data =
+               REG_ADDR(bp, PXP_VF_ADDR_CSDM_GLOBAL_START);
+       int tout = 600, interval = 100; /* wait for 60 seconds */
+
+       if (*done) {
+               BNX2X_ERR("done was non zero before message to pf was sent\n");
+               WARN_ON(true);
+               return -EINVAL;
+       }
+
+       /* Write message address */
+       writel(U64_LO(msg_mapping),
+              &zone_data->non_trigger.vf_pf_channel.msg_addr_lo);
+       writel(U64_HI(msg_mapping),
+              &zone_data->non_trigger.vf_pf_channel.msg_addr_hi);
+
+       /* make sure the address is written before FW accesses it */
+       wmb();
+
+       /* Trigger the PF FW */
+       writeb(1, &zone_data->trigger.vf_pf_channel.addr_valid);
+
+       /* Wait for PF to complete */
+       while ((tout >= 0) && (!*done)) {
+               msleep(interval);
+               tout -= 1;
+
+               /* progress indicator - HV can take its own sweet time in
+                * answering VFs...
+                */
+               DP_CONT(BNX2X_MSG_IOV, ".");
+       }
+
+       if (!*done) {
+               BNX2X_ERR("PF response has timed out\n");
+               return -EAGAIN;
+       }
+       DP(BNX2X_MSG_SP, "Got a response from PF\n");
+       return 0;
+}
+
+int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id)
+{
+       u32 me_reg;
+       int tout = 10, interval = 100; /* Wait for 1 sec */
+
+       do {
+               /* pxp traps vf read of doorbells and returns me reg value */
+               me_reg = readl(bp->doorbells);
+               if (GOOD_ME_REG(me_reg))
+                       break;
+
+               msleep(interval);
+
+               BNX2X_ERR("Invalid ME register value: 0x%08x\n. Is pf driver up?",
+                         me_reg);
+       } while (tout-- > 0);
+
+       if (!GOOD_ME_REG(me_reg)) {
+               BNX2X_ERR("Invalid ME register value: 0x%08x\n", me_reg);
+               return -EINVAL;
+       }
+
+       BNX2X_ERR("valid ME register value: 0x%08x\n", me_reg);
+
+       *vf_id = (me_reg & ME_REG_VF_NUM_MASK) >> ME_REG_VF_NUM_SHIFT;
+
+       return 0;
+}
+
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
+{
+       int rc = 0, attempts = 0;
+       struct vfpf_acquire_tlv *req = &bp->vf2pf_mbox->req.acquire;
+       struct pfvf_acquire_resp_tlv *resp = &bp->vf2pf_mbox->resp.acquire_resp;
+       u32 vf_id;
+       bool resources_acquired = false;
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));
+
+       if (bnx2x_get_vf_id(bp, &vf_id))
+               return -EAGAIN;
+
+       req->vfdev_info.vf_id = vf_id;
+       req->vfdev_info.vf_os = 0;
+
+       req->resc_request.num_rxqs = rx_count;
+       req->resc_request.num_txqs = tx_count;
+       req->resc_request.num_sbs = bp->igu_sb_cnt;
+       req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS;
+       req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS;
+
+       /* pf 2 vf bulletin board address */
+       req->bulletin_addr = bp->pf2vf_bulletin_mapping;
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       while (!resources_acquired) {
+               DP(BNX2X_MSG_SP, "attempting to acquire resources\n");
+
+               /* send acquire request */
+               rc = bnx2x_send_msg2pf(bp,
+                                      &resp->hdr.status,
+                                      bp->vf2pf_mbox_mapping);
+
+               /* PF timeout */
+               if (rc)
+                       return rc;
+
+               /* copy acquire response from buffer to bp */
+               memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));
+
+               attempts++;
+
+               /* test whether the PF accepted our request. If not, humble the
+                * the request and try again.
+                */
+               if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) {
+                       DP(BNX2X_MSG_SP, "resources acquired\n");
+                       resources_acquired = true;
+               } else if (bp->acquire_resp.hdr.status ==
+                          PFVF_STATUS_NO_RESOURCE &&
+                          attempts < VF_ACQUIRE_THRESH) {
+                       DP(BNX2X_MSG_SP,
+                          "PF unwilling to fulfill resource request. Try PF recommended amount\n");
+
+                       /* humble our request */
+                       req->resc_request.num_txqs =
+                               bp->acquire_resp.resc.num_txqs;
+                       req->resc_request.num_rxqs =
+                               bp->acquire_resp.resc.num_rxqs;
+                       req->resc_request.num_sbs =
+                               bp->acquire_resp.resc.num_sbs;
+                       req->resc_request.num_mac_filters =
+                               bp->acquire_resp.resc.num_mac_filters;
+                       req->resc_request.num_vlan_filters =
+                               bp->acquire_resp.resc.num_vlan_filters;
+                       req->resc_request.num_mc_filters =
+                               bp->acquire_resp.resc.num_mc_filters;
+
+                       /* Clear response buffer */
+                       memset(&bp->vf2pf_mbox->resp, 0,
+                              sizeof(union pfvf_tlvs));
+               } else {
+                       /* PF reports error */
+                       BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
+                                 bp->acquire_resp.hdr.status);
+                       return -EAGAIN;
+               }
+       }
+
+       /* get HW info */
+       bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff);
+       bp->link_params.chip_id = bp->common.chip_id;
+       bp->db_size = bp->acquire_resp.pfdev_info.db_size;
+       bp->common.int_block = INT_BLOCK_IGU;
+       bp->common.chip_port_mode = CHIP_2_PORT_MODE;
+       bp->igu_dsb_id = -1;
+       bp->mf_ov = 0;
+       bp->mf_mode = 0;
+       bp->common.flash_size = 0;
+       bp->flags |=
+               NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG;
+       bp->igu_sb_cnt = 1;
+       bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id;
+       strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver,
+               sizeof(bp->fw_ver));
+
+       if (is_valid_ether_addr(bp->acquire_resp.resc.current_mac_addr))
+               memcpy(bp->dev->dev_addr,
+                      bp->acquire_resp.resc.current_mac_addr,
+                      ETH_ALEN);
+
+       return 0;
+}
+
+int bnx2x_vfpf_release(struct bnx2x *bp)
+{
+       struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       u32 rc = 0, vf_id;
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req));
+
+       if (bnx2x_get_vf_id(bp, &vf_id))
+               return -EAGAIN;
+
+       req->vf_id = vf_id;
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       /* send release request */
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+       if (rc)
+               /* PF timeout */
+               return rc;
+       if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
+               /* PF released us */
+               DP(BNX2X_MSG_SP, "vf released\n");
+       } else {
+               /* PF reports error */
+               BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
+                         resp->hdr.status);
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+/* Tell PF about SB addresses */
+int bnx2x_vfpf_init(struct bnx2x *bp)
+{
+       struct vfpf_init_tlv *req = &bp->vf2pf_mbox->req.init;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       int rc, i;
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_INIT, sizeof(*req));
+
+       /* status blocks */
+       for_each_eth_queue(bp, i)
+               req->sb_addr[i] = (dma_addr_t)bnx2x_fp(bp, i,
+                                                      status_blk_mapping);
+
+       /* statistics - requests only supports single queue for now */
+       req->stats_addr = bp->fw_stats_data_mapping +
+                         offsetof(struct bnx2x_fw_stats_data, queue_stats);
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+       if (rc)
+               return rc;
+
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+               BNX2X_ERR("INIT VF failed: %d. Breaking...\n",
+                         resp->hdr.status);
+               return -EAGAIN;
+       }
+
+       DP(BNX2X_MSG_SP, "INIT VF Succeeded\n");
+       return 0;
+}
+
+/* CLOSE VF - opposite to INIT_VF */
+void bnx2x_vfpf_close_vf(struct bnx2x *bp)
+{
+       struct vfpf_close_tlv *req = &bp->vf2pf_mbox->req.close;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       int i, rc;
+       u32 vf_id;
+
+       /* If we haven't got a valid VF id, there is no sense to
+        * continue with sending messages
+        */
+       if (bnx2x_get_vf_id(bp, &vf_id))
+               goto free_irq;
+
+       /* Close the queues */
+       for_each_queue(bp, i)
+               bnx2x_vfpf_teardown_queue(bp, i);
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req));
+
+       req->vf_id = vf_id;
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+       if (rc)
+               BNX2X_ERR("Sending CLOSE failed. rc was: %d\n", rc);
+
+       else if (resp->hdr.status != PFVF_STATUS_SUCCESS)
+               BNX2X_ERR("Sending CLOSE failed: pf response was %d\n",
+                         resp->hdr.status);
+
+free_irq:
+       /* Disable HW interrupts, NAPI */
+       bnx2x_netif_stop(bp, 0);
+       /* Delete all NAPI objects */
+       bnx2x_del_all_napi(bp);
+
+       /* Release IRQs */
+       bnx2x_free_irq(bp);
+}
+
+/* ask the pf to open a queue for the vf */
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
+{
+       struct vfpf_setup_q_tlv *req = &bp->vf2pf_mbox->req.setup_q;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       struct bnx2x_fastpath *fp = &bp->fp[fp_idx];
+       u16 tpa_agg_size = 0, flags = 0;
+       int rc;
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SETUP_Q, sizeof(*req));
+
+       /* select tpa mode to request */
+       if (!fp->disable_tpa) {
+               flags |= VFPF_QUEUE_FLG_TPA;
+               flags |= VFPF_QUEUE_FLG_TPA_IPV6;
+               if (fp->mode == TPA_MODE_GRO)
+                       flags |= VFPF_QUEUE_FLG_TPA_GRO;
+               tpa_agg_size = TPA_AGG_SIZE;
+       }
+
+       /* calculate queue flags */
+       flags |= VFPF_QUEUE_FLG_STATS;
+       flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
+       flags |= IS_MF_SD(bp) ? VFPF_QUEUE_FLG_OV : 0;
+       flags |= VFPF_QUEUE_FLG_VLAN;
+       DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+
+       /* Common */
+       req->vf_qid = fp_idx;
+       req->param_valid = VFPF_RXQ_VALID | VFPF_TXQ_VALID;
+
+       /* Rx */
+       req->rxq.rcq_addr = fp->rx_comp_mapping;
+       req->rxq.rcq_np_addr = fp->rx_comp_mapping + BCM_PAGE_SIZE;
+       req->rxq.rxq_addr = fp->rx_desc_mapping;
+       req->rxq.sge_addr = fp->rx_sge_mapping;
+       req->rxq.vf_sb = fp_idx;
+       req->rxq.sb_index = HC_INDEX_ETH_RX_CQ_CONS;
+       req->rxq.hc_rate = bp->rx_ticks ? 1000000/bp->rx_ticks : 0;
+       req->rxq.mtu = bp->dev->mtu;
+       req->rxq.buf_sz = fp->rx_buf_size;
+       req->rxq.sge_buf_sz = BCM_PAGE_SIZE * PAGES_PER_SGE;
+       req->rxq.tpa_agg_sz = tpa_agg_size;
+       req->rxq.max_sge_pkt = SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
+       req->rxq.max_sge_pkt = ((req->rxq.max_sge_pkt + PAGES_PER_SGE - 1) &
+                         (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
+       req->rxq.flags = flags;
+       req->rxq.drop_flags = 0;
+       req->rxq.cache_line_log = BNX2X_RX_ALIGN_SHIFT;
+       req->rxq.stat_id = -1; /* No stats at the moment */
+
+       /* Tx */
+       req->txq.txq_addr = fp->txdata_ptr[FIRST_TX_COS_INDEX]->tx_desc_mapping;
+       req->txq.vf_sb = fp_idx;
+       req->txq.sb_index = HC_INDEX_ETH_TX_CQ_CONS_COS0;
+       req->txq.hc_rate = bp->tx_ticks ? 1000000/bp->tx_ticks : 0;
+       req->txq.flags = flags;
+       req->txq.traffic_type = LLFC_TRAFFIC_TYPE_NW;
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+       if (rc)
+               BNX2X_ERR("Sending SETUP_Q message for queue[%d] failed!\n",
+                         fp_idx);
+
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+               BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n",
+                         fp_idx, resp->hdr.status);
+               return -EINVAL;
+       }
+       return rc;
+}
+
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
+{
+       struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       int rc;
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_TEARDOWN_Q,
+                       sizeof(*req));
+
+       req->vf_qid = qidx;
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+       if (rc) {
+               BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx,
+                         rc);
+               return rc;
+       }
+
+       /* PF failed the transaction */
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+               BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
+                         resp->hdr.status);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* request pf to add a mac for the vf */
+int bnx2x_vfpf_set_mac(struct bnx2x *bp)
+{
+       struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       int rc;
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+                       sizeof(*req));
+
+       req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED;
+       req->vf_qid = 0;
+       req->n_mac_vlan_filters = 1;
+       req->filters[0].flags =
+               VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC;
+
+       /* sample bulletin board for new mac */
+       bnx2x_sample_bulletin(bp);
+
+       /* copy mac from device to request */
+       memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN);
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       /* send message to pf */
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+       if (rc) {
+               BNX2X_ERR("failed to send message to pf. rc was %d\n", rc);
+               return rc;
+       }
+
+       /* failure may mean PF was configured with a new mac for us */
+       while (resp->hdr.status == PFVF_STATUS_FAILURE) {
+               DP(BNX2X_MSG_IOV,
+                  "vfpf SET MAC failed. Check bulletin board for new posts\n");
+
+               /* check if bulletin board was updated */
+               if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) {
+                       /* copy mac from device to request */
+                       memcpy(req->filters[0].mac, bp->dev->dev_addr,
+                              ETH_ALEN);
+
+                       /* send message to pf */
+                       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status,
+                                              bp->vf2pf_mbox_mapping);
+               } else {
+                       /* no new info in bulletin */
+                       break;
+               }
+       }
+
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+               BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int bnx2x_vfpf_set_mcast(struct net_device *dev)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       int rc, i = 0;
+       struct netdev_hw_addr *ha;
+
+       if (bp->state != BNX2X_STATE_OPEN) {
+               DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
+               return -EINVAL;
+       }
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+                       sizeof(*req));
+
+       /* Get Rx mode requested */
+       DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
+
+       netdev_for_each_mc_addr(ha, dev) {
+               DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
+                  bnx2x_mc_addr(ha));
+               memcpy(req->multicast[i], bnx2x_mc_addr(ha), ETH_ALEN);
+               i++;
+       }
+
+       /* We support four PFVF_MAX_MULTICAST_PER_VF mcast
+         * addresses tops
+         */
+       if (i >= PFVF_MAX_MULTICAST_PER_VF) {
+               DP(NETIF_MSG_IFUP,
+                  "VF supports not more than %d multicast MAC addresses\n",
+                  PFVF_MAX_MULTICAST_PER_VF);
+               return -EINVAL;
+       }
+
+       req->n_multicast = i;
+       req->flags |= VFPF_SET_Q_FILTERS_MULTICAST_CHANGED;
+       req->vf_qid = 0;
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+       if (rc) {
+               BNX2X_ERR("Sending a message failed: %d\n", rc);
+               return rc;
+       }
+
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+               BNX2X_ERR("Set Rx mode/multicast failed: %d\n",
+                         resp->hdr.status);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
+{
+       int mode = bp->rx_mode;
+       struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+       struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+       int rc;
+
+       /* clear mailbox and prep first tlv */
+       bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+                       sizeof(*req));
+
+       DP(NETIF_MSG_IFUP, "Rx mode is %d\n", mode);
+
+       switch (mode) {
+       case BNX2X_RX_MODE_NONE: /* no Rx */
+               req->rx_mask = VFPF_RX_MASK_ACCEPT_NONE;
+               break;
+       case BNX2X_RX_MODE_NORMAL:
+               req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST;
+               req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+               req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+               break;
+       case BNX2X_RX_MODE_ALLMULTI:
+               req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+               req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+               req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+               break;
+       case BNX2X_RX_MODE_PROMISC:
+               req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_UNICAST;
+               req->rx_mask |= VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+               req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+               break;
+       default:
+               BNX2X_ERR("BAD rx mode (%d)\n", mode);
+               return -EINVAL;
+       }
+
+       req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
+       req->vf_qid = 0;
+
+       /* add list termination tlv */
+       bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+
+       /* output tlvs list */
+       bnx2x_dp_tlv_list(bp, req);
+
+       rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+       if (rc)
+               BNX2X_ERR("Sending a message failed: %d\n", rc);
+
+       if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+               BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
+               return -EINVAL;
+       }
+
+       return rc;
+}
+
+/* General service functions */
+static void storm_memset_vf_mbx_ack(struct bnx2x *bp, u16 abs_fid)
+{
+       u32 addr = BAR_CSTRORM_INTMEM +
+                  CSTORM_VF_PF_CHANNEL_STATE_OFFSET(abs_fid);
+
+       REG_WR8(bp, addr, VF_PF_CHANNEL_STATE_READY);
+}
+
+static void storm_memset_vf_mbx_valid(struct bnx2x *bp, u16 abs_fid)
+{
+       u32 addr = BAR_CSTRORM_INTMEM +
+                  CSTORM_VF_PF_CHANNEL_VALID_OFFSET(abs_fid);
+
+       REG_WR8(bp, addr, 1);
+}
+
+static inline void bnx2x_set_vf_mbxs_valid(struct bnx2x *bp)
+{
+       int i;
+
+       for_each_vf(bp, i)
+               storm_memset_vf_mbx_valid(bp, bnx2x_vf(bp, i, abs_vfid));
+}
+
+/* enable vf_pf mailbox (aka vf-pf-chanell) */
+void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid)
+{
+       bnx2x_vf_flr_clnup_epilog(bp, abs_vfid);
+
+       /* enable the mailbox in the FW */
+       storm_memset_vf_mbx_ack(bp, abs_vfid);
+       storm_memset_vf_mbx_valid(bp, abs_vfid);
+
+       /* enable the VF access to the mailbox */
+       bnx2x_vf_enable_access(bp, abs_vfid);
+}
+
+/* this works only on !E1h */
+static int bnx2x_copy32_vf_dmae(struct bnx2x *bp, u8 from_vf,
+                               dma_addr_t pf_addr, u8 vfid, u32 vf_addr_hi,
+                               u32 vf_addr_lo, u32 len32)
+{
+       struct dmae_command dmae;
+
+       if (CHIP_IS_E1x(bp)) {
+               BNX2X_ERR("Chip revision does not support VFs\n");
+               return DMAE_NOT_RDY;
+       }
+
+       if (!bp->dmae_ready) {
+               BNX2X_ERR("DMAE is not ready, can not copy\n");
+               return DMAE_NOT_RDY;
+       }
+
+       /* set opcode and fixed command fields */
+       bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_PCI, DMAE_DST_PCI);
+
+       if (from_vf) {
+               dmae.opcode_iov = (vfid << DMAE_COMMAND_SRC_VFID_SHIFT) |
+                       (DMAE_SRC_VF << DMAE_COMMAND_SRC_VFPF_SHIFT) |
+                       (DMAE_DST_PF << DMAE_COMMAND_DST_VFPF_SHIFT);
+
+               dmae.opcode |= (DMAE_C_DST << DMAE_COMMAND_C_FUNC_SHIFT);
+
+               dmae.src_addr_lo = vf_addr_lo;
+               dmae.src_addr_hi = vf_addr_hi;
+               dmae.dst_addr_lo = U64_LO(pf_addr);
+               dmae.dst_addr_hi = U64_HI(pf_addr);
+       } else {
+               dmae.opcode_iov = (vfid << DMAE_COMMAND_DST_VFID_SHIFT) |
+                       (DMAE_DST_VF << DMAE_COMMAND_DST_VFPF_SHIFT) |
+                       (DMAE_SRC_PF << DMAE_COMMAND_SRC_VFPF_SHIFT);
+
+               dmae.opcode |= (DMAE_C_SRC << DMAE_COMMAND_C_FUNC_SHIFT);
+
+               dmae.src_addr_lo = U64_LO(pf_addr);
+               dmae.src_addr_hi = U64_HI(pf_addr);
+               dmae.dst_addr_lo = vf_addr_lo;
+               dmae.dst_addr_hi = vf_addr_hi;
+       }
+       dmae.len = len32;
+       bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_DMAE);
+
+       /* issue the command and wait for completion */
+       return bnx2x_issue_dmae_with_comp(bp, &dmae);
+}
+
+static void bnx2x_vf_mbx_resp(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf->index);
+       u64 vf_addr;
+       dma_addr_t pf_addr;
+       u16 length, type;
+       int rc;
+       struct pfvf_general_resp_tlv *resp = &mbx->msg->resp.general_resp;
+
+       /* prepare response */
+       type = mbx->first_tlv.tl.type;
+       length = type == CHANNEL_TLV_ACQUIRE ?
+               sizeof(struct pfvf_acquire_resp_tlv) :
+               sizeof(struct pfvf_general_resp_tlv);
+       bnx2x_add_tlv(bp, resp, 0, type, length);
+       resp->hdr.status = bnx2x_pfvf_status_codes(vf->op_rc);
+       bnx2x_add_tlv(bp, resp, length, CHANNEL_TLV_LIST_END,
+                     sizeof(struct channel_list_end_tlv));
+       bnx2x_dp_tlv_list(bp, resp);
+       DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
+          mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+
+       /* send response */
+       vf_addr = HILO_U64(mbx->vf_addr_hi, mbx->vf_addr_lo) +
+                 mbx->first_tlv.resp_msg_offset;
+       pf_addr = mbx->msg_mapping +
+                 offsetof(struct bnx2x_vf_mbx_msg, resp);
+
+       /* copy the response body, if there is one, before the header, as the vf
+        * is sensitive to the header being written
+        */
+       if (resp->hdr.tl.length > sizeof(u64)) {
+               length = resp->hdr.tl.length - sizeof(u64);
+               vf_addr += sizeof(u64);
+               pf_addr += sizeof(u64);
+               rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
+                                         U64_HI(vf_addr),
+                                         U64_LO(vf_addr),
+                                         length/4);
+               if (rc) {
+                       BNX2X_ERR("Failed to copy response body to VF %d\n",
+                                 vf->abs_vfid);
+                       goto mbx_error;
+               }
+               vf_addr -= sizeof(u64);
+               pf_addr -= sizeof(u64);
+       }
+
+       /* ack the FW */
+       storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+       mmiowb();
+
+       /* initiate dmae to send the response */
+       mbx->flags &= ~VF_MSG_INPROCESS;
+
+       /* copy the response header including status-done field,
+        * must be last dmae, must be after FW is acked
+        */
+       rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
+                                 U64_HI(vf_addr),
+                                 U64_LO(vf_addr),
+                                 sizeof(u64)/4);
+
+       /* unlock channel mutex */
+       bnx2x_unlock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
+
+       if (rc) {
+               BNX2X_ERR("Failed to copy response status to VF %d\n",
+                         vf->abs_vfid);
+               goto mbx_error;
+       }
+       return;
+
+mbx_error:
+       bnx2x_vf_release(bp, vf, false); /* non blocking */
+}
+
+static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                     struct bnx2x_vf_mbx *mbx, int vfop_status)
+{
+       int i;
+       struct pfvf_acquire_resp_tlv *resp = &mbx->msg->resp.acquire_resp;
+       struct pf_vf_resc *resc = &resp->resc;
+       u8 status = bnx2x_pfvf_status_codes(vfop_status);
+
+       memset(resp, 0, sizeof(*resp));
+
+       /* fill in pfdev info */
+       resp->pfdev_info.chip_num = bp->common.chip_id;
+       resp->pfdev_info.db_size = (1 << BNX2X_DB_SHIFT);
+       resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2;
+       resp->pfdev_info.pf_cap = (PFVF_CAP_RSS |
+                                  /* PFVF_CAP_DHC |*/ PFVF_CAP_TPA);
+       bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver,
+                         sizeof(resp->pfdev_info.fw_ver));
+
+       if (status == PFVF_STATUS_NO_RESOURCE ||
+           status == PFVF_STATUS_SUCCESS) {
+               /* set resources numbers, if status equals NO_RESOURCE these
+                * are max possible numbers
+                */
+               resc->num_rxqs = vf_rxq_count(vf) ? :
+                       bnx2x_vf_max_queue_cnt(bp, vf);
+               resc->num_txqs = vf_txq_count(vf) ? :
+                       bnx2x_vf_max_queue_cnt(bp, vf);
+               resc->num_sbs = vf_sb_count(vf);
+               resc->num_mac_filters = vf_mac_rules_cnt(vf);
+               resc->num_vlan_filters = vf_vlan_rules_cnt(vf);
+               resc->num_mc_filters = 0;
+
+               if (status == PFVF_STATUS_SUCCESS) {
+                       /* fill in the allocated resources */
+                       struct pf_vf_bulletin_content *bulletin =
+                               BP_VF_BULLETIN(bp, vf->index);
+
+                       for_each_vfq(vf, i)
+                               resc->hw_qid[i] =
+                                       vfq_qzone_id(vf, vfq_get(vf, i));
+
+                       for_each_vf_sb(vf, i) {
+                               resc->hw_sbs[i].hw_sb_id = vf_igu_sb(vf, i);
+                               resc->hw_sbs[i].sb_qid = vf_hc_qzone(vf, i);
+                       }
+
+                       /* if a mac has been set for this vf, supply it */
+                       if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) {
+                               memcpy(resc->current_mac_addr, bulletin->mac,
+                                      ETH_ALEN);
+                       }
+               }
+       }
+
+       DP(BNX2X_MSG_IOV, "VF[%d] ACQUIRE_RESPONSE: pfdev_info- chip_num=0x%x, db_size=%d, idx_per_sb=%d, pf_cap=0x%x\n"
+          "resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d, n_mcs-%d, fw_ver: '%s'\n",
+          vf->abs_vfid,
+          resp->pfdev_info.chip_num,
+          resp->pfdev_info.db_size,
+          resp->pfdev_info.indices_per_sb,
+          resp->pfdev_info.pf_cap,
+          resc->num_rxqs,
+          resc->num_txqs,
+          resc->num_sbs,
+          resc->num_mac_filters,
+          resc->num_vlan_filters,
+          resc->num_mc_filters,
+          resp->pfdev_info.fw_ver);
+
+       DP_CONT(BNX2X_MSG_IOV, "hw_qids- [ ");
+       for (i = 0; i < vf_rxq_count(vf); i++)
+               DP_CONT(BNX2X_MSG_IOV, "%d ", resc->hw_qid[i]);
+       DP_CONT(BNX2X_MSG_IOV, "], sb_info- [ ");
+       for (i = 0; i < vf_sb_count(vf); i++)
+               DP_CONT(BNX2X_MSG_IOV, "%d:%d ",
+                       resc->hw_sbs[i].hw_sb_id,
+                       resc->hw_sbs[i].sb_qid);
+       DP_CONT(BNX2X_MSG_IOV, "]\n");
+
+       /* send the response */
+       vf->op_rc = vfop_status;
+       bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                struct bnx2x_vf_mbx *mbx)
+{
+       int rc;
+       struct vfpf_acquire_tlv *acquire = &mbx->msg->req.acquire;
+
+       /* log vfdef info */
+       DP(BNX2X_MSG_IOV,
+          "VF[%d] ACQUIRE: vfdev_info- vf_id %d, vf_os %d resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d, n_mcs-%d\n",
+          vf->abs_vfid, acquire->vfdev_info.vf_id, acquire->vfdev_info.vf_os,
+          acquire->resc_request.num_rxqs, acquire->resc_request.num_txqs,
+          acquire->resc_request.num_sbs, acquire->resc_request.num_mac_filters,
+          acquire->resc_request.num_vlan_filters,
+          acquire->resc_request.num_mc_filters);
+
+       /* acquire the resources */
+       rc = bnx2x_vf_acquire(bp, vf, &acquire->resc_request);
+
+       /* store address of vf's bulletin board */
+       vf->bulletin_map = acquire->bulletin_addr;
+
+       /* response */
+       bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc);
+}
+
+static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                             struct bnx2x_vf_mbx *mbx)
+{
+       struct vfpf_init_tlv *init = &mbx->msg->req.init;
+
+       /* record ghost addresses from vf message */
+       vf->spq_map = init->spq_addr;
+       vf->fw_stat_map = init->stats_addr;
+       vf->op_rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr);
+
+       /* response */
+       bnx2x_vf_mbx_resp(bp, vf);
+}
+
+/* convert MBX queue-flags to standard SP queue-flags */
+static void bnx2x_vf_mbx_set_q_flags(u32 mbx_q_flags,
+                                    unsigned long *sp_q_flags)
+{
+       if (mbx_q_flags & VFPF_QUEUE_FLG_TPA)
+               __set_bit(BNX2X_Q_FLG_TPA, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_TPA_IPV6)
+               __set_bit(BNX2X_Q_FLG_TPA_IPV6, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_TPA_GRO)
+               __set_bit(BNX2X_Q_FLG_TPA_GRO, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_STATS)
+               __set_bit(BNX2X_Q_FLG_STATS, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_OV)
+               __set_bit(BNX2X_Q_FLG_OV, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_VLAN)
+               __set_bit(BNX2X_Q_FLG_VLAN, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_COS)
+               __set_bit(BNX2X_Q_FLG_COS, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_HC)
+               __set_bit(BNX2X_Q_FLG_HC, sp_q_flags);
+       if (mbx_q_flags & VFPF_QUEUE_FLG_DHC)
+               __set_bit(BNX2X_Q_FLG_DHC, sp_q_flags);
+}
+
+static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                struct bnx2x_vf_mbx *mbx)
+{
+       struct vfpf_setup_q_tlv *setup_q = &mbx->msg->req.setup_q;
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+
+       /* verify vf_qid */
+       if (setup_q->vf_qid >= vf_rxq_count(vf)) {
+               BNX2X_ERR("vf_qid %d invalid, max queue count is %d\n",
+                         setup_q->vf_qid, vf_rxq_count(vf));
+               vf->op_rc = -EINVAL;
+               goto response;
+       }
+
+       /* tx queues must be setup alongside rx queues thus if the rx queue
+        * is not marked as valid there's nothing to do.
+        */
+       if (setup_q->param_valid & (VFPF_RXQ_VALID|VFPF_TXQ_VALID)) {
+               struct bnx2x_vf_queue *q = vfq_get(vf, setup_q->vf_qid);
+               unsigned long q_type = 0;
+
+               struct bnx2x_queue_init_params *init_p;
+               struct bnx2x_queue_setup_params *setup_p;
+
+               /* reinit the VF operation context */
+               memset(&vf->op_params.qctor, 0 , sizeof(vf->op_params.qctor));
+               setup_p = &vf->op_params.qctor.prep_qsetup;
+               init_p =  &vf->op_params.qctor.qstate.params.init;
+
+               /* activate immediately */
+               __set_bit(BNX2X_Q_FLG_ACTIVE, &setup_p->flags);
+
+               if (setup_q->param_valid & VFPF_TXQ_VALID) {
+                       struct bnx2x_txq_setup_params *txq_params =
+                               &setup_p->txq_params;
+
+                       __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+
+                       /* save sb resource index */
+                       q->sb_idx = setup_q->txq.vf_sb;
+
+                       /* tx init */
+                       init_p->tx.hc_rate = setup_q->txq.hc_rate;
+                       init_p->tx.sb_cq_index = setup_q->txq.sb_index;
+
+                       bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+                                                &init_p->tx.flags);
+
+                       /* tx setup - flags */
+                       bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+                                                &setup_p->flags);
+
+                       /* tx setup - general, nothing */
+
+                       /* tx setup - tx */
+                       txq_params->dscr_map = setup_q->txq.txq_addr;
+                       txq_params->sb_cq_index = setup_q->txq.sb_index;
+                       txq_params->traffic_type = setup_q->txq.traffic_type;
+
+                       bnx2x_vfop_qctor_dump_tx(bp, vf, init_p, setup_p,
+                                                q->index, q->sb_idx);
+               }
+
+               if (setup_q->param_valid & VFPF_RXQ_VALID) {
+                       struct bnx2x_rxq_setup_params *rxq_params =
+                                                       &setup_p->rxq_params;
+
+                       __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+
+                       /* Note: there is no support for different SBs
+                        * for TX and RX
+                        */
+                       q->sb_idx = setup_q->rxq.vf_sb;
+
+                       /* rx init */
+                       init_p->rx.hc_rate = setup_q->rxq.hc_rate;
+                       init_p->rx.sb_cq_index = setup_q->rxq.sb_index;
+                       bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+                                                &init_p->rx.flags);
+
+                       /* rx setup - flags */
+                       bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+                                                &setup_p->flags);
+
+                       /* rx setup - general */
+                       setup_p->gen_params.mtu = setup_q->rxq.mtu;
+
+                       /* rx setup - rx */
+                       rxq_params->drop_flags = setup_q->rxq.drop_flags;
+                       rxq_params->dscr_map = setup_q->rxq.rxq_addr;
+                       rxq_params->sge_map = setup_q->rxq.sge_addr;
+                       rxq_params->rcq_map = setup_q->rxq.rcq_addr;
+                       rxq_params->rcq_np_map = setup_q->rxq.rcq_np_addr;
+                       rxq_params->buf_sz = setup_q->rxq.buf_sz;
+                       rxq_params->tpa_agg_sz = setup_q->rxq.tpa_agg_sz;
+                       rxq_params->max_sges_pkt = setup_q->rxq.max_sge_pkt;
+                       rxq_params->sge_buf_sz = setup_q->rxq.sge_buf_sz;
+                       rxq_params->cache_line_log =
+                               setup_q->rxq.cache_line_log;
+                       rxq_params->sb_cq_index = setup_q->rxq.sb_index;
+
+                       bnx2x_vfop_qctor_dump_rx(bp, vf, init_p, setup_p,
+                                                q->index, q->sb_idx);
+               }
+               /* complete the preparations */
+               bnx2x_vfop_qctor_prep(bp, vf, q, &vf->op_params.qctor, q_type);
+
+               vf->op_rc = bnx2x_vfop_qsetup_cmd(bp, vf, &cmd, q->index);
+               if (vf->op_rc)
+                       goto response;
+               return;
+       }
+response:
+       bnx2x_vf_mbx_resp(bp, vf);
+}
+
+enum bnx2x_vfop_filters_state {
+          BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+          BNX2X_VFOP_MBX_Q_FILTERS_VLANS,
+          BNX2X_VFOP_MBX_Q_FILTERS_RXMODE,
+          BNX2X_VFOP_MBX_Q_FILTERS_MCAST,
+          BNX2X_VFOP_MBX_Q_FILTERS_DONE
+};
+
+static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
+                                    struct bnx2x_virtf *vf,
+                                    struct vfpf_set_q_filters_tlv *tlv,
+                                    struct bnx2x_vfop_filters **pfl,
+                                    u32 type_flag)
+{
+       int i, j;
+       struct bnx2x_vfop_filters *fl = NULL;
+       size_t fsz;
+
+       fsz = tlv->n_mac_vlan_filters * sizeof(struct bnx2x_vfop_filter) +
+               sizeof(struct bnx2x_vfop_filters);
+
+       fl = kzalloc(fsz, GFP_KERNEL);
+       if (!fl)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&fl->head);
+
+       for (i = 0, j = 0; i < tlv->n_mac_vlan_filters; i++) {
+               struct vfpf_q_mac_vlan_filter *msg_filter = &tlv->filters[i];
+
+               if ((msg_filter->flags & type_flag) != type_flag)
+                       continue;
+               if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) {
+                       fl->filters[j].mac = msg_filter->mac;
+                       fl->filters[j].type = BNX2X_VFOP_FILTER_MAC;
+               } else {
+                       fl->filters[j].vid = msg_filter->vlan_tag;
+                       fl->filters[j].type = BNX2X_VFOP_FILTER_VLAN;
+               }
+               fl->filters[j].add =
+                       (msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ?
+                       true : false;
+               list_add_tail(&fl->filters[j++].link, &fl->head);
+       }
+       if (list_empty(&fl->head))
+               kfree(fl);
+       else
+               *pfl = fl;
+
+       return 0;
+}
+
+static void bnx2x_vf_mbx_dp_q_filter(struct bnx2x *bp, int msglvl, int idx,
+                                      struct vfpf_q_mac_vlan_filter *filter)
+{
+       DP(msglvl, "MAC-VLAN[%d] -- flags=0x%x\n", idx, filter->flags);
+       if (filter->flags & VFPF_Q_FILTER_VLAN_TAG_VALID)
+               DP_CONT(msglvl, ", vlan=%d", filter->vlan_tag);
+       if (filter->flags & VFPF_Q_FILTER_DEST_MAC_VALID)
+               DP_CONT(msglvl, ", MAC=%pM", filter->mac);
+       DP_CONT(msglvl, "\n");
+}
+
+static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl,
+                                      struct vfpf_set_q_filters_tlv *filters)
+{
+       int i;
+
+       if (filters->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED)
+               for (i = 0; i < filters->n_mac_vlan_filters; i++)
+                       bnx2x_vf_mbx_dp_q_filter(bp, msglvl, i,
+                                                &filters->filters[i]);
+
+       if (filters->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED)
+               DP(msglvl, "RX-MASK=0x%x\n", filters->rx_mask);
+
+       if (filters->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED)
+               for (i = 0; i < filters->n_multicast; i++)
+                       DP(msglvl, "MULTICAST=%pM\n", filters->multicast[i]);
+}
+
+#define VFPF_MAC_FILTER                VFPF_Q_FILTER_DEST_MAC_VALID
+#define VFPF_VLAN_FILTER       VFPF_Q_FILTER_VLAN_TAG_VALID
+
+static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       int rc;
+
+       struct vfpf_set_q_filters_tlv *msg =
+               &BP_VF_MBX(bp, vf->index)->msg->req.set_q_filters;
+
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       enum bnx2x_vfop_filters_state state = vfop->state;
+
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vfop_mbx_qfilters,
+               .block = false,
+       };
+
+       DP(BNX2X_MSG_IOV, "STATE: %d\n", state);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       switch (state) {
+       case BNX2X_VFOP_MBX_Q_FILTERS_MACS:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_VLANS;
+
+               /* check for any vlan/mac changes */
+               if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+                       /* build mac list */
+                       struct bnx2x_vfop_filters *fl = NULL;
+
+                       vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+                                                            VFPF_MAC_FILTER);
+                       if (vfop->rc)
+                               goto op_err;
+
+                       if (fl) {
+                               /* set mac list */
+                               rc = bnx2x_vfop_mac_list_cmd(bp, vf, &cmd, fl,
+                                                            msg->vf_qid,
+                                                            false);
+                               if (rc) {
+                                       vfop->rc = rc;
+                                       goto op_err;
+                               }
+                               return;
+                       }
+               }
+               /* fall through */
+
+       case BNX2X_VFOP_MBX_Q_FILTERS_VLANS:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_RXMODE;
+
+               /* check for any vlan/mac changes */
+               if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+                       /* build vlan list */
+                       struct bnx2x_vfop_filters *fl = NULL;
+
+                       vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+                                                            VFPF_VLAN_FILTER);
+                       if (vfop->rc)
+                               goto op_err;
+
+                       if (fl) {
+                               /* set vlan list */
+                               rc = bnx2x_vfop_vlan_list_cmd(bp, vf, &cmd, fl,
+                                                             msg->vf_qid,
+                                                             false);
+                               if (rc) {
+                                       vfop->rc = rc;
+                                       goto op_err;
+                               }
+                               return;
+                       }
+               }
+               /* fall through */
+
+       case BNX2X_VFOP_MBX_Q_FILTERS_RXMODE:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_MCAST;
+
+               if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
+                       unsigned long accept = 0;
+
+                       /* covert VF-PF if mask to bnx2x accept flags */
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
+                               __set_bit(BNX2X_ACCEPT_UNICAST, &accept);
+
+                       if (msg->rx_mask &
+                                       VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST)
+                               __set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
+
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_UNICAST)
+                               __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept);
+
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_MULTICAST)
+                               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept);
+
+                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_BROADCAST)
+                               __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
+
+                       /* A packet arriving the vf's mac should be accepted
+                        * with any vlan
+                        */
+                       __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
+
+                       /* set rx-mode */
+                       rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd,
+                                                  msg->vf_qid, accept);
+                       if (rc) {
+                               vfop->rc = rc;
+                               goto op_err;
+                       }
+                       return;
+               }
+               /* fall through */
+
+       case BNX2X_VFOP_MBX_Q_FILTERS_MCAST:
+               /* next state */
+               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_DONE;
+
+               if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
+                       /* set mcasts */
+                       rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, msg->multicast,
+                                                 msg->n_multicast, false);
+                       if (rc) {
+                               vfop->rc = rc;
+                               goto op_err;
+                       }
+                       return;
+               }
+               /* fall through */
+op_done:
+       case BNX2X_VFOP_MBX_Q_FILTERS_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+op_err:
+       BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
+                 vf->abs_vfid, msg->vf_qid, vfop->rc);
+       goto op_done;
+
+       default:
+               bnx2x_vfop_default(state);
+       }
+}
+
+static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp,
+                                       struct bnx2x_virtf *vf,
+                                       struct bnx2x_vfop_cmd *cmd)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       if (vfop) {
+               bnx2x_vfop_opset(BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+                                bnx2x_vfop_mbx_qfilters, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mbx_qfilters,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
+static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
+                                      struct bnx2x_virtf *vf,
+                                      struct bnx2x_vf_mbx *mbx)
+{
+       struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
+       struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index);
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+
+       /* if a mac was already set for this VF via the set vf mac ndo, we only
+        * accept mac configurations of that mac. Why accept them at all?
+        * because PF may have been unable to configure the mac at the time
+        * since queue was not set up.
+        */
+       if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) {
+               /* once a mac was set by ndo can only accept a single mac... */
+               if (filters->n_mac_vlan_filters > 1) {
+                       BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called\n",
+                                 vf->abs_vfid);
+                       vf->op_rc = -EPERM;
+                       goto response;
+               }
+
+               /* ...and only the mac set by the ndo */
+               if (filters->n_mac_vlan_filters == 1 &&
+                   memcmp(filters->filters->mac, bulletin->mac, ETH_ALEN)) {
+                       BNX2X_ERR("VF[%d] requested the addition of a mac address not matching the one configured by set_vf_mac ndo\n",
+                                 vf->abs_vfid);
+
+                       vf->op_rc = -EPERM;
+                       goto response;
+               }
+       }
+
+       /* verify vf_qid */
+       if (filters->vf_qid > vf_rxq_count(vf))
+               goto response;
+
+       DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n",
+          vf->abs_vfid,
+          filters->vf_qid);
+
+       /* print q_filter message */
+       bnx2x_vf_mbx_dp_q_filters(bp, BNX2X_MSG_IOV, filters);
+
+       vf->op_rc = bnx2x_vfop_mbx_qfilters_cmd(bp, vf, &cmd);
+       if (vf->op_rc)
+               goto response;
+       return;
+
+response:
+       bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_teardown_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                   struct bnx2x_vf_mbx *mbx)
+{
+       int qid = mbx->msg->req.q_op.vf_qid;
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+
+       DP(BNX2X_MSG_IOV, "VF[%d] Q_TEARDOWN: vf_qid=%d\n",
+          vf->abs_vfid, qid);
+
+       vf->op_rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qid);
+       if (vf->op_rc)
+               bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_close_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                 struct bnx2x_vf_mbx *mbx)
+{
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+
+       DP(BNX2X_MSG_IOV, "VF[%d] VF_CLOSE\n", vf->abs_vfid);
+
+       vf->op_rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
+       if (vf->op_rc)
+               bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_release_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                   struct bnx2x_vf_mbx *mbx)
+{
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+
+       DP(BNX2X_MSG_IOV, "VF[%d] VF_RELEASE\n", vf->abs_vfid);
+
+       vf->op_rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+       if (vf->op_rc)
+               bnx2x_vf_mbx_resp(bp, vf);
+}
+
+/* dispatch request */
+static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                 struct bnx2x_vf_mbx *mbx)
+{
+       int i;
+
+       /* check if tlv type is known */
+       if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) {
+               /* Lock the per vf op mutex and note the locker's identity.
+                * The unlock will take place in mbx response.
+                */
+               bnx2x_lock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
+
+               /* switch on the opcode */
+               switch (mbx->first_tlv.tl.type) {
+               case CHANNEL_TLV_ACQUIRE:
+                       bnx2x_vf_mbx_acquire(bp, vf, mbx);
+                       break;
+               case CHANNEL_TLV_INIT:
+                       bnx2x_vf_mbx_init_vf(bp, vf, mbx);
+                       break;
+               case CHANNEL_TLV_SETUP_Q:
+                       bnx2x_vf_mbx_setup_q(bp, vf, mbx);
+                       break;
+               case CHANNEL_TLV_SET_Q_FILTERS:
+                       bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
+                       break;
+               case CHANNEL_TLV_TEARDOWN_Q:
+                       bnx2x_vf_mbx_teardown_q(bp, vf, mbx);
+                       break;
+               case CHANNEL_TLV_CLOSE:
+                       bnx2x_vf_mbx_close_vf(bp, vf, mbx);
+                       break;
+               case CHANNEL_TLV_RELEASE:
+                       bnx2x_vf_mbx_release_vf(bp, vf, mbx);
+                       break;
+               }
+
+       } else {
+               /* unknown TLV - this may belong to a VF driver from the future
+                * - a version written after this PF driver was written, which
+                * supports features unknown as of yet. Too bad since we don't
+                * support them. Or this may be because someone wrote a crappy
+                * VF driver and is sending garbage over the channel.
+                */
+               BNX2X_ERR("unknown TLV. type %d length %d. first 20 bytes of mailbox buffer:\n",
+                         mbx->first_tlv.tl.type, mbx->first_tlv.tl.length);
+               for (i = 0; i < 20; i++)
+                       DP_CONT(BNX2X_MSG_IOV, "%x ",
+                               mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
+
+               /* test whether we can respond to the VF (do we have an address
+                * for it?)
+                */
+               if (vf->state == VF_ACQUIRED) {
+                       /* mbx_resp uses the op_rc of the VF */
+                       vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
+
+                       /* notify the VF that we do not support this request */
+                       bnx2x_vf_mbx_resp(bp, vf);
+               } else {
+                       /* can't send a response since this VF is unknown to us
+                        * just unlock the channel and be done with.
+                        */
+                       bnx2x_unlock_vf_pf_channel(bp, vf,
+                                                  mbx->first_tlv.tl.type);
+               }
+       }
+}
+
+/* handle new vf-pf message */
+void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
+{
+       struct bnx2x_virtf *vf;
+       struct bnx2x_vf_mbx *mbx;
+       u8 vf_idx;
+       int rc;
+
+       DP(BNX2X_MSG_IOV,
+          "vf pf event received: vfid %d, address_hi %x, address lo %x",
+          vfpf_event->vf_id, vfpf_event->msg_addr_hi, vfpf_event->msg_addr_lo);
+       /* Sanity checks consider removing later */
+
+       /* check if the vf_id is valid */
+       if (vfpf_event->vf_id - BP_VFDB(bp)->sriov.first_vf_in_pf >
+           BNX2X_NR_VIRTFN(bp)) {
+               BNX2X_ERR("Illegal vf_id %d max allowed: %d\n",
+                         vfpf_event->vf_id, BNX2X_NR_VIRTFN(bp));
+               goto mbx_done;
+       }
+       vf_idx = bnx2x_vf_idx_by_abs_fid(bp, vfpf_event->vf_id);
+       mbx = BP_VF_MBX(bp, vf_idx);
+
+       /* verify an event is not currently being processed -
+        * debug failsafe only
+        */
+       if (mbx->flags & VF_MSG_INPROCESS) {
+               BNX2X_ERR("Previous message is still being processed, vf_id %d\n",
+                         vfpf_event->vf_id);
+               goto mbx_done;
+       }
+       vf = BP_VF(bp, vf_idx);
+
+       /* save the VF message address */
+       mbx->vf_addr_hi = vfpf_event->msg_addr_hi;
+       mbx->vf_addr_lo = vfpf_event->msg_addr_lo;
+       DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
+          mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+
+       /* dmae to get the VF request */
+       rc = bnx2x_copy32_vf_dmae(bp, true, mbx->msg_mapping, vf->abs_vfid,
+                                 mbx->vf_addr_hi, mbx->vf_addr_lo,
+                                 sizeof(union vfpf_tlvs)/4);
+       if (rc) {
+               BNX2X_ERR("Failed to copy request VF %d\n", vf->abs_vfid);
+               goto mbx_error;
+       }
+
+       /* process the VF message header */
+       mbx->first_tlv = mbx->msg->req.first_tlv;
+
+       /* dispatch the request (will prepare the response) */
+       bnx2x_vf_mbx_request(bp, vf, mbx);
+       goto mbx_done;
+
+mbx_error:
+       bnx2x_vf_release(bp, vf, false); /* non blocking */
+mbx_done:
+       return;
+}
+
+/* propagate local bulletin board to vf */
+int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf)
+{
+       struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf);
+       dma_addr_t pf_addr = BP_VF_BULLETIN_DMA(bp)->mapping +
+               vf * BULLETIN_CONTENT_SIZE;
+       dma_addr_t vf_addr = bnx2x_vf(bp, vf, bulletin_map);
+       int rc;
+
+       /* can only update vf after init took place */
+       if (bnx2x_vf(bp, vf, state) != VF_ENABLED &&
+           bnx2x_vf(bp, vf, state) != VF_ACQUIRED)
+               return 0;
+
+       /* increment bulletin board version and compute crc */
+       bulletin->version++;
+       bulletin->length = BULLETIN_CONTENT_SIZE;
+       bulletin->crc = bnx2x_crc_vf_bulletin(bp, bulletin);
+
+       /* propagate bulletin board via dmae to vm memory */
+       rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr,
+                                 bnx2x_vf(bp, vf, abs_vfid), U64_HI(vf_addr),
+                                 U64_LO(vf_addr), bulletin->length / 4);
+       return rc;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
new file mode 100644 (file)
index 0000000..bfc80ba
--- /dev/null
@@ -0,0 +1,360 @@
+/* bnx2x_vfpf.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2011-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Ariel Elior <ariele@broadcom.com>
+ */
+#ifndef VF_PF_IF_H
+#define VF_PF_IF_H
+
+#ifdef CONFIG_BNX2X_SRIOV
+
+/* Common definitions for all HVs */
+struct vf_pf_resc_request {
+       u8  num_rxqs;
+       u8  num_txqs;
+       u8  num_sbs;
+       u8  num_mac_filters;
+       u8  num_vlan_filters;
+       u8  num_mc_filters; /* No limit  so superfluous */
+};
+
+struct hw_sb_info {
+       u8 hw_sb_id;    /* aka absolute igu id, used to ack the sb */
+       u8 sb_qid;      /* used to update DHC for sb */
+};
+
+/* HW VF-PF channel definitions
+ * A.K.A VF-PF mailbox
+ */
+#define TLV_BUFFER_SIZE                        1024
+#define PF_VF_BULLETIN_SIZE            512
+
+#define VFPF_QUEUE_FLG_TPA             0x0001
+#define VFPF_QUEUE_FLG_TPA_IPV6                0x0002
+#define VFPF_QUEUE_FLG_TPA_GRO         0x0004
+#define VFPF_QUEUE_FLG_CACHE_ALIGN     0x0008
+#define VFPF_QUEUE_FLG_STATS           0x0010
+#define VFPF_QUEUE_FLG_OV              0x0020
+#define VFPF_QUEUE_FLG_VLAN            0x0040
+#define VFPF_QUEUE_FLG_COS             0x0080
+#define VFPF_QUEUE_FLG_HC              0x0100
+#define VFPF_QUEUE_FLG_DHC             0x0200
+
+#define VFPF_QUEUE_DROP_IP_CS_ERR      (1 << 0)
+#define VFPF_QUEUE_DROP_TCP_CS_ERR     (1 << 1)
+#define VFPF_QUEUE_DROP_TTL0           (1 << 2)
+#define VFPF_QUEUE_DROP_UDP_CS_ERR     (1 << 3)
+
+#define VFPF_RX_MASK_ACCEPT_NONE               0x00000000
+#define VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST    0x00000001
+#define VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST  0x00000002
+#define VFPF_RX_MASK_ACCEPT_ALL_UNICAST                0x00000004
+#define VFPF_RX_MASK_ACCEPT_ALL_MULTICAST      0x00000008
+#define VFPF_RX_MASK_ACCEPT_BROADCAST          0x00000010
+#define BULLETIN_CONTENT_SIZE          (sizeof(struct pf_vf_bulletin_content))
+#define BULLETIN_ATTEMPTS      5 /* crc failures before throwing towel */
+#define BULLETIN_CRC_SEED      0
+
+enum {
+       PFVF_STATUS_WAITING = 0,
+       PFVF_STATUS_SUCCESS,
+       PFVF_STATUS_FAILURE,
+       PFVF_STATUS_NOT_SUPPORTED,
+       PFVF_STATUS_NO_RESOURCE
+};
+
+/* vf pf channel tlvs */
+/* general tlv header (used for both vf->pf request and pf->vf response) */
+struct channel_tlv {
+       u16 type;
+       u16 length;
+};
+
+/* header of first vf->pf tlv carries the offset used to calculate response
+ * buffer address
+ */
+struct vfpf_first_tlv {
+       struct channel_tlv tl;
+       u32 resp_msg_offset;
+};
+
+/* header of pf->vf tlvs, carries the status of handling the request */
+struct pfvf_tlv {
+       struct channel_tlv tl;
+       u8 status;
+       u8 padding[3];
+};
+
+/* response tlv used for most tlvs */
+struct pfvf_general_resp_tlv {
+       struct pfvf_tlv hdr;
+};
+
+/* used to terminate and pad a tlv list */
+struct channel_list_end_tlv {
+       struct channel_tlv tl;
+       u8 padding[4];
+};
+
+/* Acquire */
+struct vfpf_acquire_tlv {
+       struct vfpf_first_tlv first_tlv;
+
+       struct vf_pf_vfdev_info {
+               /* the following fields are for debug purposes */
+               u8  vf_id;              /* ME register value */
+               u8  vf_os;              /* e.g. Linux, W2K8 */
+               u8 padding[2];
+       } vfdev_info;
+
+       struct vf_pf_resc_request resc_request;
+
+       aligned_u64 bulletin_addr;
+};
+
+/* simple operation request on queue */
+struct vfpf_q_op_tlv {
+       struct vfpf_first_tlv   first_tlv;
+       u8 vf_qid;
+       u8 padding[3];
+};
+
+/* acquire response tlv - carries the allocated resources */
+struct pfvf_acquire_resp_tlv {
+       struct pfvf_tlv hdr;
+       struct pf_vf_pfdev_info {
+               u32 chip_num;
+               u32 pf_cap;
+#define PFVF_CAP_RSS           0x00000001
+#define PFVF_CAP_DHC           0x00000002
+#define PFVF_CAP_TPA           0x00000004
+               char fw_ver[32];
+               u16 db_size;
+               u8  indices_per_sb;
+               u8  padding;
+       } pfdev_info;
+       struct pf_vf_resc {
+               /* in case of status NO_RESOURCE in message hdr, pf will fill
+                * this struct with suggested amount of resources for next
+                * acquire request
+                */
+#define PFVF_MAX_QUEUES_PER_VF         16
+#define PFVF_MAX_SBS_PER_VF            16
+               struct hw_sb_info hw_sbs[PFVF_MAX_SBS_PER_VF];
+               u8      hw_qid[PFVF_MAX_QUEUES_PER_VF];
+               u8      num_rxqs;
+               u8      num_txqs;
+               u8      num_sbs;
+               u8      num_mac_filters;
+               u8      num_vlan_filters;
+               u8      num_mc_filters;
+               u8      permanent_mac_addr[ETH_ALEN];
+               u8      current_mac_addr[ETH_ALEN];
+               u8      padding[2];
+       } resc;
+};
+
+/* Init VF */
+struct vfpf_init_tlv {
+       struct vfpf_first_tlv first_tlv;
+       aligned_u64 sb_addr[PFVF_MAX_SBS_PER_VF]; /* vf_sb based */
+       aligned_u64 spq_addr;
+       aligned_u64 stats_addr;
+};
+
+/* Setup Queue */
+struct vfpf_setup_q_tlv {
+       struct vfpf_first_tlv first_tlv;
+
+       struct vf_pf_rxq_params {
+               /* physical addresses */
+               aligned_u64 rcq_addr;
+               aligned_u64 rcq_np_addr;
+               aligned_u64 rxq_addr;
+               aligned_u64 sge_addr;
+
+               /* sb + hc info */
+               u8  vf_sb;              /* index in hw_sbs[] */
+               u8  sb_index;           /* Index in the SB */
+               u16 hc_rate;            /* desired interrupts per sec. */
+                                       /* valid iff VFPF_QUEUE_FLG_HC */
+               /* rx buffer info */
+               u16 mtu;
+               u16 buf_sz;
+               u16 flags;              /* VFPF_QUEUE_FLG_X flags */
+               u16 stat_id;            /* valid iff VFPF_QUEUE_FLG_STATS */
+
+               /* valid iff VFPF_QUEUE_FLG_TPA */
+               u16 sge_buf_sz;
+               u16 tpa_agg_sz;
+               u8 max_sge_pkt;
+
+               u8 drop_flags;          /* VFPF_QUEUE_DROP_X, for Linux VMs
+                                        * all the flags are turned off
+                                        */
+
+               u8 cache_line_log;      /* VFPF_QUEUE_FLG_CACHE_ALIGN */
+               u8 padding;
+       } rxq;
+
+       struct vf_pf_txq_params {
+               /* physical addresses */
+               aligned_u64 txq_addr;
+
+               /* sb + hc info */
+               u8  vf_sb;              /* index in hw_sbs[] */
+               u8  sb_index;           /* Index in the SB */
+               u16 hc_rate;            /* desired interrupts per sec. */
+                                       /* valid iff VFPF_QUEUE_FLG_HC */
+               u32 flags;              /* VFPF_QUEUE_FLG_X flags */
+               u16 stat_id;            /* valid iff VFPF_QUEUE_FLG_STATS */
+               u8  traffic_type;       /* see in setup_context() */
+               u8  padding;
+       } txq;
+
+       u8 vf_qid;                      /* index in hw_qid[] */
+       u8 param_valid;
+#define VFPF_RXQ_VALID         0x01
+#define VFPF_TXQ_VALID         0x02
+       u8 padding[2];
+};
+
+/* Set Queue Filters */
+struct vfpf_q_mac_vlan_filter {
+       u32 flags;
+#define VFPF_Q_FILTER_DEST_MAC_VALID   0x01
+#define VFPF_Q_FILTER_VLAN_TAG_VALID   0x02
+#define VFPF_Q_FILTER_SET_MAC          0x100   /* set/clear */
+       u8  mac[ETH_ALEN];
+       u16 vlan_tag;
+};
+
+/* configure queue filters */
+struct vfpf_set_q_filters_tlv {
+       struct vfpf_first_tlv first_tlv;
+
+       u32 flags;
+#define VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED    0x01
+#define VFPF_SET_Q_FILTERS_MULTICAST_CHANGED   0x02
+#define VFPF_SET_Q_FILTERS_RX_MASK_CHANGED     0x04
+
+       u8 vf_qid;                      /* index in hw_qid[] */
+       u8 n_mac_vlan_filters;
+       u8 n_multicast;
+       u8 padding;
+
+#define PFVF_MAX_MAC_FILTERS                   16
+#define PFVF_MAX_VLAN_FILTERS                  16
+#define PFVF_MAX_FILTERS               (PFVF_MAX_MAC_FILTERS +\
+                                        PFVF_MAX_VLAN_FILTERS)
+       struct vfpf_q_mac_vlan_filter filters[PFVF_MAX_FILTERS];
+
+#define PFVF_MAX_MULTICAST_PER_VF              32
+       u8  multicast[PFVF_MAX_MULTICAST_PER_VF][ETH_ALEN];
+
+       u32 rx_mask;    /* see mask constants at the top of the file */
+};
+
+/* close VF (disable VF) */
+struct vfpf_close_tlv {
+       struct vfpf_first_tlv   first_tlv;
+       u16                     vf_id;  /* for debug */
+       u8 padding[2];
+};
+
+/* release the VF's acquired resources */
+struct vfpf_release_tlv {
+       struct vfpf_first_tlv   first_tlv;
+       u16                     vf_id;
+       u8 padding[2];
+};
+
+struct tlv_buffer_size {
+       u8 tlv_buffer[TLV_BUFFER_SIZE];
+};
+
+union vfpf_tlvs {
+       struct vfpf_first_tlv           first_tlv;
+       struct vfpf_acquire_tlv         acquire;
+       struct vfpf_init_tlv            init;
+       struct vfpf_close_tlv           close;
+       struct vfpf_q_op_tlv            q_op;
+       struct vfpf_setup_q_tlv         setup_q;
+       struct vfpf_set_q_filters_tlv   set_q_filters;
+       struct vfpf_release_tlv         release;
+       struct channel_list_end_tlv     list_end;
+       struct tlv_buffer_size          tlv_buf_size;
+};
+
+union pfvf_tlvs {
+       struct pfvf_general_resp_tlv    general_resp;
+       struct pfvf_acquire_resp_tlv    acquire_resp;
+       struct channel_list_end_tlv     list_end;
+       struct tlv_buffer_size          tlv_buf_size;
+};
+
+/* This is a structure which is allocated in the VF, which the PF may update
+ * when it deems it necessary to do so. The bulletin board is sampled
+ * periodically by the VF. A copy per VF is maintained in the PF (to prevent
+ * loss of data upon multiple updates (or the need for read modify write)).
+ */
+struct pf_vf_bulletin_size {
+       u8 size[PF_VF_BULLETIN_SIZE];
+};
+
+struct pf_vf_bulletin_content {
+       u32 crc;                        /* crc of structure to ensure is not in
+                                        * mid-update
+                                        */
+       u16 version;
+       u16 length;
+
+       aligned_u64 valid_bitmap;       /* bitmap indicating which fields
+                                        * hold valid values
+                                        */
+
+#define MAC_ADDR_VALID         0       /* alert the vf that a new mac address
+                                        * is available for it
+                                        */
+
+       u8 mac[ETH_ALEN];
+       u8 padding[2];
+};
+
+union pf_vf_bulletin {
+       struct pf_vf_bulletin_content content;
+       struct pf_vf_bulletin_size size;
+};
+
+#define MAX_TLVS_IN_LIST 50
+
+enum channel_tlvs {
+       CHANNEL_TLV_NONE,
+       CHANNEL_TLV_ACQUIRE,
+       CHANNEL_TLV_INIT,
+       CHANNEL_TLV_SETUP_Q,
+       CHANNEL_TLV_SET_Q_FILTERS,
+       CHANNEL_TLV_TEARDOWN_Q,
+       CHANNEL_TLV_CLOSE,
+       CHANNEL_TLV_RELEASE,
+       CHANNEL_TLV_PF_RELEASE_VF,
+       CHANNEL_TLV_LIST_END,
+       CHANNEL_TLV_FLR,
+       CHANNEL_TLV_PF_SET_MAC,
+       CHANNEL_TLV_MAX
+};
+
+#endif /* CONFIG_BNX2X_SRIOV */
+#endif /* VF_PF_IF_H */
index df8c30d1a52cc4d1fc35e6fb8f7cf6c1b73d31c3..1c4dadc7ebbb75bdd9b76ec4264ea9c8e4280f7f 100644 (file)
@@ -4816,6 +4816,8 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
                return err;
        }
 
+       ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
+
        return 0;
 }
 
@@ -5136,6 +5138,7 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
        if (ret)
                return ret;
 
+       ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
        return 0;
 }
 
@@ -5387,6 +5390,7 @@ static void cnic_stop_hw(struct cnic_dev *dev)
                }
                cnic_shutdown_rings(dev);
                cp->stop_cm(dev);
+               cp->ethdev->drv_state &= ~CNIC_DRV_STATE_HANDLES_IRQ;
                clear_bit(CNIC_F_CNIC_UP, &dev->flags);
                RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL);
                synchronize_rcu();
index 2a35436f90956744a2efa443062001a4acde1727..0c9367a0f57d92ef56c5f0f89dea166e0e00b180 100644 (file)
@@ -179,6 +179,7 @@ struct cnic_eth_dev {
 #define CNIC_DRV_STATE_NO_ISCSI_OOO    0x00000004
 #define CNIC_DRV_STATE_NO_ISCSI                0x00000008
 #define CNIC_DRV_STATE_NO_FCOE         0x00000010
+#define CNIC_DRV_STATE_HANDLES_IRQ     0x00000020
        u32             chip_id;
        u32             max_kwqe_pending;
        struct pci_dev  *pdev;
index 3a1c8a3cf7c91af5ada39f9ded17e604212b2c01..e9b35da375cb4c3b7bf5c31a1b03d18097ad44c1 100644 (file)
@@ -2385,7 +2385,7 @@ static int sbmac_mii_probe(struct net_device *dev)
                return -ENXIO;
        }
 
-       phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &sbmac_mii_poll, 0,
+       phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &sbmac_mii_poll,
                              PHY_INTERFACE_MODE_GMII);
        if (IS_ERR(phy_dev)) {
                printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
index bdb086934cd95de72cd1aa02cf1cb4b6baaaafc3..ab07026a36e310cb9790928490cd1f104512f4ac 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005-2012 Broadcom Corporation.
+ * Copyright (C) 2005-2013 Broadcom Corporation.
  *
  * Firmware is:
  *     Derived from proprietary unpublished source code,
@@ -93,10 +93,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 #define DRV_MODULE_NAME                "tg3"
 #define TG3_MAJ_NUM                    3
-#define TG3_MIN_NUM                    128
+#define TG3_MIN_NUM                    129
 #define DRV_MODULE_VERSION     \
        __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE     "December 03, 2012"
+#define DRV_MODULE_RELDATE     "January 06, 2013"
 
 #define RESET_KIND_SHUTDOWN    0
 #define RESET_KIND_INIT                1
@@ -330,6 +330,9 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57762)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5762)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5725)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5727)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -2013,8 +2016,8 @@ static int tg3_phy_init(struct tg3 *tp)
        phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 
        /* Attach the MAC to the PHY. */
-       phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link,
-                            phydev->dev_flags, phydev->interface);
+       phydev = phy_connect(tp->dev, dev_name(&phydev->dev),
+                            tg3_adjust_link, phydev->interface);
        if (IS_ERR(phydev)) {
                dev_err(&tp->pdev->dev, "Could not attach to PHY\n");
                return PTR_ERR(phydev);
@@ -2644,6 +2647,9 @@ out:
                tg3_writephy(tp, MII_TG3_FET_PTEST, 0x12);
        }
 
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5762_A0)
+               tg3_phydsp_write(tp, 0xffb, 0x4000);
+
        tg3_phy_toggle_automdix(tp, 1);
        tg3_phy_set_wirespeed(tp);
        return 0;
@@ -4049,6 +4055,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
                        tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
                        /* Fall through */
                case ASIC_REV_5720:
+               case ASIC_REV_5762:
                        if (!tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
                                tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, val |
                                                 MII_TG3_DSP_CH34TP2_HIBW01);
@@ -5496,7 +5503,8 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
 
        val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
              (6 << TX_LENGTHS_IPG_SHIFT);
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                val |= tr32(MAC_TX_LENGTHS) &
                       (TX_LENGTHS_JMB_FRM_LEN_MSK |
                        TX_LENGTHS_CNT_DWN_VAL_MSK);
@@ -8687,7 +8695,8 @@ static void tg3_rings_reset(struct tg3 *tp)
                limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16;
        else if (tg3_flag(tp, 5717_PLUS))
                limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4;
-       else if (tg3_flag(tp, 57765_CLASS))
+       else if (tg3_flag(tp, 57765_CLASS) ||
+                GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2;
        else
                limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE;
@@ -8704,6 +8713,7 @@ static void tg3_rings_reset(struct tg3 *tp)
        else if (!tg3_flag(tp, 5705_PLUS))
                limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16;
        else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+                GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762 ||
                 tg3_flag(tp, 57765_CLASS))
                limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4;
        else
@@ -8994,9 +9004,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 
        /* Enable MAC control of LPI */
        if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
-               tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
-                      TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
-                      TG3_CPMU_EEE_LNKIDL_UART_IDL);
+               val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+                     TG3_CPMU_EEE_LNKIDL_UART_IDL;
+               if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
+                       val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;
+
+               tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);
 
                tw32_f(TG3_CPMU_EEE_CTRL,
                       TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
@@ -9171,7 +9184,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
                        val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK;
                if (!tg3_flag(tp, 57765_CLASS) &&
-                   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+                   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+                   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5762)
                        val |= DMA_RWCTRL_TAGGED_STAT_WA;
                tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl);
        } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
@@ -9323,7 +9337,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                        tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
                             val | BDINFO_FLAGS_USE_EXT_RECV);
                        if (!tg3_flag(tp, USE_JUMBO_BDFLAG) ||
-                           tg3_flag(tp, 57765_CLASS))
+                           tg3_flag(tp, 57765_CLASS) ||
+                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                                tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
                                     NIC_SRAM_RX_JUMBO_BUFFER_DESC);
                } else {
@@ -9365,7 +9380,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
              (6 << TX_LENGTHS_IPG_SHIFT) |
              (32 << TX_LENGTHS_SLOT_TIME_SHIFT);
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                val |= tr32(MAC_TX_LENGTHS) &
                       (TX_LENGTHS_JMB_FRM_LEN_MSK |
                        TX_LENGTHS_CNT_DWN_VAL_MSK);
@@ -9419,7 +9435,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
                rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN;
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                rdmac_mode |= tr32(RDMAC_MODE) & RDMAC_MODE_H2BNC_VLAN_DET;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
@@ -9427,8 +9444,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
            tg3_flag(tp, 57765_PLUS)) {
-               val = tr32(TG3_RDMA_RSRVCTRL_REG);
-               if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) {
+               u32 tgtreg;
+
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
+                       tgtreg = TG3_RDMA_RSRVCTRL_REG2;
+               else
+                       tgtreg = TG3_RDMA_RSRVCTRL_REG;
+
+               val = tr32(tgtreg);
+               if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762) {
                        val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK |
                                 TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK |
                                 TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK);
@@ -9436,14 +9461,21 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                               TG3_RDMA_RSRVCTRL_FIFO_LWM_1_5K |
                               TG3_RDMA_RSRVCTRL_FIFO_HWM_1_5K;
                }
-               tw32(TG3_RDMA_RSRVCTRL_REG,
-                    val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
+               tw32(tgtreg, val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
-               val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
-               tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val |
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762) {
+               u32 tgtreg;
+
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
+                       tgtreg = TG3_LSO_RD_DMA_CRPTEN_CTRL2;
+               else
+                       tgtreg = TG3_LSO_RD_DMA_CRPTEN_CTRL;
+
+               val = tr32(tgtreg);
+               tw32(tgtreg, val |
                     TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K |
                     TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K);
        }
@@ -9676,7 +9708,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762) {
                val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE;
                tp->tx_mode &= ~val;
                tp->tx_mode |= tr32(MAC_TX_MODE) & val;
@@ -12357,7 +12390,8 @@ static int tg3_test_memory(struct tg3 *tp)
 
        if (tg3_flag(tp, 5717_PLUS))
                mem_tbl = mem_tbl_5717;
-       else if (tg3_flag(tp, 57765_CLASS))
+       else if (tg3_flag(tp, 57765_CLASS) ||
+                GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                mem_tbl = mem_tbl_57765;
        else if (tg3_flag(tp, 5755_PLUS))
                mem_tbl = mem_tbl_5755;
@@ -13698,6 +13732,22 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
        nvcfg1 = tr32(NVRAM_CFG1);
        nvmpinstrp = nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK;
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762) {
+               if (!(nvcfg1 & NVRAM_CFG1_5762VENDOR_MASK)) {
+                       tg3_flag_set(tp, NO_NVRAM);
+                       return;
+               }
+
+               switch (nvmpinstrp) {
+               case FLASH_5762_EEPROM_HD:
+                       nvmpinstrp = FLASH_5720_EEPROM_HD;
+                       break;
+               case FLASH_5762_EEPROM_LD:
+                       nvmpinstrp = FLASH_5720_EEPROM_LD;
+                       break;
+               }
+       }
+
        switch (nvmpinstrp) {
        case FLASH_5720_EEPROM_HD:
        case FLASH_5720_EEPROM_LD:
@@ -13801,6 +13851,17 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
        tg3_nvram_get_pagesize(tp, nvcfg1);
        if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528)
                tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS);
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762) {
+               u32 val;
+
+               if (tg3_nvram_read(tp, 0, &val))
+                       return;
+
+               if (val != TG3_EEPROM_MAGIC &&
+                   (val & TG3_EEPROM_MAGIC_FW_MSK) != TG3_EEPROM_MAGIC_FW)
+                       tg3_flag_set(tp, NO_NVRAM);
+       }
 }
 
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
@@ -13850,7 +13911,8 @@ static void tg3_nvram_init(struct tg3 *tp)
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
                         GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
                        tg3_get_5717_nvram_info(tp);
-               else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+               else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+                        GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                        tg3_get_5720_nvram_info(tp);
                else
                        tg3_get_nvram_info(tp);
@@ -14152,6 +14214,39 @@ done:
                device_set_wakeup_capable(&tp->pdev->dev, false);
 }
 
+static int tg3_ape_otp_read(struct tg3 *tp, u32 offset, u32 *val)
+{
+       int i, err;
+       u32 val2, off = offset * 8;
+
+       err = tg3_nvram_lock(tp);
+       if (err)
+               return err;
+
+       tg3_ape_write32(tp, TG3_APE_OTP_ADDR, off | APE_OTP_ADDR_CPU_ENABLE);
+       tg3_ape_write32(tp, TG3_APE_OTP_CTRL, APE_OTP_CTRL_PROG_EN |
+                       APE_OTP_CTRL_CMD_RD | APE_OTP_CTRL_START);
+       tg3_ape_read32(tp, TG3_APE_OTP_CTRL);
+       udelay(10);
+
+       for (i = 0; i < 100; i++) {
+               val2 = tg3_ape_read32(tp, TG3_APE_OTP_STATUS);
+               if (val2 & APE_OTP_STATUS_CMD_DONE) {
+                       *val = tg3_ape_read32(tp, TG3_APE_OTP_RD_DATA);
+                       break;
+               }
+               udelay(10);
+       }
+
+       tg3_ape_write32(tp, TG3_APE_OTP_CTRL, 0);
+
+       tg3_nvram_unlock(tp);
+       if (val2 & APE_OTP_STATUS_CMD_DONE)
+               return 0;
+
+       return -EBUSY;
+}
+
 static int tg3_issue_otp_command(struct tg3 *tp, u32 cmd)
 {
        int i;
@@ -14311,6 +14406,7 @@ static int tg3_phy_probe(struct tg3 *tp)
        if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762 ||
             (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
              tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) ||
             (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
@@ -14691,6 +14787,8 @@ static void tg3_read_dash_ver(struct tg3 *tp)
 
        if (tg3_flag(tp, APE_HAS_NCSI))
                fwtype = "NCSI";
+       else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725)
+               fwtype = "SMASH";
        else
                fwtype = "DASH";
 
@@ -14704,6 +14802,31 @@ static void tg3_read_dash_ver(struct tg3 *tp)
                 (apedata & APE_FW_VERSION_BLDMSK));
 }
 
+static void tg3_read_otp_ver(struct tg3 *tp)
+{
+       u32 val, val2;
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5762)
+               return;
+
+       if (!tg3_ape_otp_read(tp, OTP_ADDRESS_MAGIC0, &val) &&
+           !tg3_ape_otp_read(tp, OTP_ADDRESS_MAGIC0 + 4, &val2) &&
+           TG3_OTP_MAGIC0_VALID(val)) {
+               u64 val64 = (u64) val << 32 | val2;
+               u32 ver = 0;
+               int i, vlen;
+
+               for (i = 0; i < 7; i++) {
+                       if ((val64 & 0xff) == 0)
+                               break;
+                       ver = val64 & 0xff;
+                       val64 >>= 8;
+               }
+               vlen = strlen(tp->fw_ver);
+               snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " .%02d", ver);
+       }
+}
+
 static void tg3_read_fw_ver(struct tg3 *tp)
 {
        u32 val;
@@ -14714,6 +14837,7 @@ static void tg3_read_fw_ver(struct tg3 *tp)
 
        if (tg3_flag(tp, NO_NVRAM)) {
                strcat(tp->fw_ver, "sb");
+               tg3_read_otp_ver(tp);
                return;
        }
 
@@ -14800,7 +14924,10 @@ static void tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
                    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C ||
                    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
                    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
-                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
+                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720 ||
+                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5762 ||
+                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725 ||
+                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5727)
                        reg = TG3PCI_GEN2_PRODID_ASICREV;
                else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
                         tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
@@ -14837,7 +14964,8 @@ static void tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
                tg3_flag_set(tp, 57765_CLASS);
 
-       if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
+       if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS) ||
+            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                tg3_flag_set(tp, 57765_PLUS);
 
        /* Intentionally exclude ASIC_REV_5906 */
@@ -15128,7 +15256,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                tg3_flag_set(tp, LRG_PROD_RING_CAP);
 
        if (tg3_flag(tp, 57765_PLUS) &&
@@ -15329,21 +15458,18 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
                                              &val);
                        tp->pci_fn = val & 0x7;
                }
-       } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
-               tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val);
-               if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) ==
-                   NIC_SRAM_CPMUSTAT_SIG) {
-                       tp->pci_fn = val & TG3_CPMU_STATUS_FMSK_5717;
-                       tp->pci_fn = tp->pci_fn ? 1 : 0;
-               }
-       } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+       } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+                  GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
                tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val);
-               if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) ==
-                   NIC_SRAM_CPMUSTAT_SIG) {
+               if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) != NIC_SRAM_CPMUSTAT_SIG)
+                       val = tr32(TG3_CPMU_STATUS);
+
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+                       tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5717) ? 1 : 0;
+               else
                        tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5719) >>
                                     TG3_CPMU_STATUS_FSHFT_5719;
-               }
        }
 
        /* Get eeprom hw config before calling tg3_set_power_state().
@@ -15406,6 +15532,10 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
                                              GRC_LCLCTRL_GPIO_OUTPUT0;
        }
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
+               tp->grc_local_ctrl |=
+                       tr32(GRC_LOCAL_CTRL) & GRC_LCLCTRL_GPIO_UART_SEL;
+
        /* Switch out of Vaux if it is a NIC */
        tg3_pwrsrc_switch_to_vmain(tp);
 
@@ -15496,7 +15626,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 
        /* Initialize data/descriptor byte/word swapping. */
        val = tr32(GRC_MODE);
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA |
                        GRC_MODE_WORD_SWAP_B2HRX_DATA |
                        GRC_MODE_B2HRX_ENABLE |
@@ -15658,7 +15789,6 @@ static int tg3_get_macaddr_sparc(struct tg3 *tp)
        addr = of_get_property(dp, "local-mac-address", &len);
        if (addr && len == 6) {
                memcpy(dev->dev_addr, addr, 6);
-               memcpy(dev->perm_addr, dev->dev_addr, 6);
                return 0;
        }
        return -ENODEV;
@@ -15669,7 +15799,6 @@ static int tg3_get_default_macaddr_sparc(struct tg3 *tp)
        struct net_device *dev = tp->dev;
 
        memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-       memcpy(dev->perm_addr, idprom->id_ethaddr, 6);
        return 0;
 }
 #endif
@@ -15746,7 +15875,6 @@ static int tg3_get_device_address(struct tg3 *tp)
 #endif
                return -EINVAL;
        }
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        return 0;
 }
 
@@ -16253,6 +16381,7 @@ static char *tg3_phy_string(struct tg3 *tp)
        case TG3_PHY_ID_BCM57765:       return "57765";
        case TG3_PHY_ID_BCM5719C:       return "5719C";
        case TG3_PHY_ID_BCM5720C:       return "5720C";
+       case TG3_PHY_ID_BCM5762:        return "5762C";
        case TG3_PHY_ID_BCM8002:        return "8002/serdes";
        case 0:                 return "serdes";
        default:                return "unknown";
@@ -16429,7 +16558,10 @@ static int tg3_init_one(struct pci_dev *pdev,
            tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C ||
            tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
            tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
-           tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720) {
+           tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720 ||
+           tp->pdev->device == TG3PCI_DEVICE_TIGON3_5762 ||
+           tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725 ||
+           tp->pdev->device == TG3PCI_DEVICE_TIGON3_5727) {
                tg3_flag_set(tp, ENABLE_APE);
                tp->aperegs = pci_ioremap_bar(pdev, BAR_2);
                if (!tp->aperegs) {
@@ -16624,7 +16756,8 @@ static int tg3_init_one(struct pci_dev *pdev,
        pci_set_drvdata(pdev, dev);
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5762)
                tg3_flag_set(tp, PTP_CAPABLE);
 
        if (tg3_flag(tp, 5717_PLUS)) {
index d330e81f5793ad47e8f6257d3e08c728719c9651..9cd88a4b9a5f58fdf4f168258269cda476563c87 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2007-2012 Broadcom Corporation.
+ * Copyright (C) 2007-2013 Broadcom Corporation.
  */
 
 #ifndef _T3_H
@@ -65,6 +65,9 @@
 #define  TG3PCI_DEVICE_TIGON3_57766     0x1686
 #define  TG3PCI_DEVICE_TIGON3_57786     0x16b3
 #define  TG3PCI_DEVICE_TIGON3_57782     0x16b7
+#define  TG3PCI_DEVICE_TIGON3_5762      0x1687
+#define  TG3PCI_DEVICE_TIGON3_5725      0x1643
+#define  TG3PCI_DEVICE_TIGON3_5727      0x16f3
 /* 0x04 --> 0x2c unused */
 #define TG3PCI_SUBVENDOR_ID_BROADCOM           PCI_VENDOR_ID_BROADCOM
 #define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6   0x1644
 #define  CHIPREV_ID_57765_A0            0x57785000
 #define  CHIPREV_ID_5719_A0             0x05719000
 #define  CHIPREV_ID_5720_A0             0x05720000
+#define  CHIPREV_ID_5762_A0             0x05762000
 #define  GET_ASIC_REV(CHIP_REV_ID)     ((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700                         0x07
 #define   ASIC_REV_5701                         0x00
 #define   ASIC_REV_5719                         0x5719
 #define   ASIC_REV_5720                         0x5720
 #define   ASIC_REV_57766                0x57766
+#define   ASIC_REV_5762                         0x5762
 #define  GET_CHIP_REV(CHIP_REV_ID)     ((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX               0x70
 #define   CHIPREV_5700_BX               0x71
 #define  SG_DIG_AUTONEG_ERROR           0x00000001
 #define TG3_TX_TSTAMP_LSB              0x000005c0
 #define TG3_TX_TSTAMP_MSB              0x000005c4
-#define  TG3_TSTAMP_MASK                0x7fffffffffffffff
+#define  TG3_TSTAMP_MASK                0x7fffffffffffffffLL
 /* 0x5c8 --> 0x600 unused */
 #define MAC_TX_MAC_STATE_BASE          0x00000600 /* 16 bytes */
 #define MAC_RX_MAC_STATE_BASE          0x00000610 /* 20 bytes */
 #define TG3_CPMU_EEE_LNKIDL_CTRL       0x000036bc
 #define  TG3_CPMU_EEE_LNKIDL_PCIE_NL0   0x01000000
 #define  TG3_CPMU_EEE_LNKIDL_UART_IDL   0x00000004
+#define  TG3_CPMU_EEE_LNKIDL_APE_TX_MT  0x00000002
 /* 0x36c0 --> 0x36d0 unused */
 
 #define TG3_CPMU_EEE_CTRL              0x000036d0
 #define  RDMAC_STATUS_FIFOURUN          0x00000080
 #define  RDMAC_STATUS_FIFOOREAD                 0x00000100
 #define  RDMAC_STATUS_LNGREAD           0x00000200
-/* 0x4808 --> 0x4900 unused */
+/* 0x4808 --> 0x4890 unused */
+
+#define TG3_RDMA_RSRVCTRL_REG2         0x00004890
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL2    0x000048a0
 
 #define TG3_RDMA_RSRVCTRL_REG          0x00004900
 #define TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX         0x00000004
 #define  FLASH_VENDOR_SST_SMALL                 0x00000001
 #define  FLASH_VENDOR_SST_LARGE                 0x02000001
 #define  NVRAM_CFG1_5752VENDOR_MASK     0x03c00003
+#define  NVRAM_CFG1_5762VENDOR_MASK     0x03e00003
 #define  FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ    0x00000000
 #define  FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ   0x02000000
 #define  FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED  0x02000003
 #define  FLASH_5717VENDOR_ST_45USPT     0x03400001
 #define  FLASH_5720_EEPROM_HD           0x00000001
 #define  FLASH_5720_EEPROM_LD           0x00000003
+#define  FLASH_5762_EEPROM_HD           0x02000001
+#define  FLASH_5762_EEPROM_LD           0x02000003
 #define  FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000
 #define  FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002
 #define  FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001
 #define  APE_LOCK_REQ_DRIVER            0x00001000
 #define TG3_APE_LOCK_GRANT             0x004c
 #define  APE_LOCK_GRANT_DRIVER          0x00001000
+#define TG3_APE_OTP_CTRL               0x00e8
+#define  APE_OTP_CTRL_PROG_EN           0x200000
+#define  APE_OTP_CTRL_CMD_RD            0x000000
+#define  APE_OTP_CTRL_START             0x000001
+#define TG3_APE_OTP_STATUS             0x00ec
+#define  APE_OTP_STATUS_CMD_DONE        0x000001
+#define TG3_APE_OTP_ADDR               0x00f0
+#define  APE_OTP_ADDR_CPU_ENABLE        0x80000000
+#define TG3_APE_OTP_RD_DATA            0x00f8
+
+#define OTP_ADDRESS_MAGIC0              0x00000050
+#define TG3_OTP_MAGIC0_VALID(val)              \
+       ((((val) & 0xf0000000) == 0xa0000000) ||\
+        (((val) & 0x0f000000) == 0x0a000000))
 
 /* APE shared memory.  Accessible through BAR1 */
 #define TG3_APE_SHMEM_BASE             0x4000
@@ -3206,6 +3232,7 @@ struct tg3 {
 #define TG3_PHY_ID_BCM57765            0x5c0d8a40
 #define TG3_PHY_ID_BCM5719C            0x5c0d8a20
 #define TG3_PHY_ID_BCM5720C            0x5c0d8b60
+#define TG3_PHY_ID_BCM5762             0x85803780
 #define TG3_PHY_ID_BCM5906             0xdc00ac40
 #define TG3_PHY_ID_BCM8002             0x60010140
 #define TG3_PHY_ID_INVALID             0xffffffff
@@ -3230,6 +3257,7 @@ struct tg3 {
         (X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
         (X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
         (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
+        (X) == TG3_PHY_ID_BCM5720C || (X) == TG3_PHY_ID_BCM5762 || \
         (X) == TG3_PHY_ID_BCM8002)
 
        u32                             phy_flags;
@@ -3320,9 +3348,7 @@ struct tg3 {
        const struct firmware           *fw;
        u32                             fw_len; /* includes BSS */
 
-#if IS_ENABLED(CONFIG_HWMON)
        struct device                   *hwmon_dev;
-#endif
        bool                            link_up;
 };
 
index a9b0830fb39d90b3227fe14741c8a4a3f09dc2d6..352190b9ebe722ec271a7dd7a6d764fceba1044b 100644 (file)
@@ -287,7 +287,7 @@ static int macb_mii_probe(struct net_device *dev)
        }
 
        /* attach the mac to the phy */
-       ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0,
+       ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
                                 bp->phy_interface);
        if (ret) {
                netdev_err(dev, "Could not attach to PHY\n");
index f7f02900f6508f0c8a7f8b6b41558aa85550e291..a170065b597382ed9408239d98c36cec98a535a2 100644 (file)
@@ -1463,7 +1463,6 @@ static int xgmac_set_mac_address(struct net_device *dev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
        xgmac_set_mac_addr(ioaddr, dev->dev_addr, 0);
index c8fdeaae56c0a70bbb28e147979738f5533e2fdb..20d2085f61c54639bb6baa6926b9a9a09bf8d82d 100644 (file)
@@ -131,7 +131,7 @@ static void t1_set_rxmode(struct net_device *dev)
 static void link_report(struct port_info *p)
 {
        if (!netif_carrier_ok(p->dev))
-               printk(KERN_INFO "%s: link down\n", p->dev->name);
+               netdev_info(p->dev, "link down\n");
        else {
                const char *s = "10Mbps";
 
@@ -141,9 +141,9 @@ static void link_report(struct port_info *p)
                        case SPEED_100:   s = "100Mbps"; break;
                }
 
-               printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
-                      p->dev->name, s,
-                      p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+               netdev_info(p->dev, "link up, %s, %s-duplex\n",
+                           s, p->link_config.duplex == DUPLEX_FULL
+                           ? "full" : "half");
        }
 }
 
@@ -976,19 +976,13 @@ static const struct net_device_ops cxgb_netdev_ops = {
 
 static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       static int version_printed;
-
        int i, err, pci_using_dac = 0;
        unsigned long mmio_start, mmio_len;
        const struct board_info *bi;
        struct adapter *adapter = NULL;
        struct port_info *pi;
 
-       if (!version_printed) {
-               printk(KERN_INFO "%s - version %s\n", DRV_DESCRIPTION,
-                      DRV_VERSION);
-               ++version_printed;
-       }
+       pr_info_once("%s - version %s\n", DRV_DESCRIPTION, DRV_VERSION);
 
        err = pci_enable_device(pdev);
        if (err)
@@ -1124,8 +1118,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        for (i = 0; i < bi->port_number; ++i) {
                err = register_netdev(adapter->port[i].dev);
                if (err)
-                       pr_warning("%s: cannot register net device %s, skipping\n",
-                                  pci_name(pdev), adapter->port[i].dev->name);
+                       pr_warn("%s: cannot register net device %s, skipping\n",
+                               pci_name(pdev), adapter->port[i].dev->name);
                else {
                        /*
                         * Change the name we use for messages to the name of
@@ -1143,10 +1137,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto out_release_adapter_res;
        }
 
-       printk(KERN_INFO "%s: %s (rev %d), %s %dMHz/%d-bit\n", adapter->name,
-              bi->desc, adapter->params.chip_revision,
-              adapter->params.pci.is_pcix ? "PCIX" : "PCI",
-              adapter->params.pci.speed, adapter->params.pci.width);
+       pr_info("%s: %s (rev %d), %s %dMHz/%d-bit\n",
+               adapter->name, bi->desc, adapter->params.chip_revision,
+               adapter->params.pci.is_pcix ? "PCIX" : "PCI",
+               adapter->params.pci.speed, adapter->params.pci.width);
 
        /*
         * Set the T1B ASIC and memory clocks.
index d84872e8817131233c9f949615ec9b0492d1ebe8..482976925154d1dad9d18eebeda003ce1088d2db 100644 (file)
@@ -1822,8 +1822,8 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 */
                if (unlikely(skb->len < ETH_HLEN ||
                             skb->len > dev->mtu + eth_hdr_len(skb->data))) {
-                       pr_debug("%s: packet size %d hdr %d mtu%d\n", dev->name,
-                                skb->len, eth_hdr_len(skb->data), dev->mtu);
+                       netdev_dbg(dev, "packet size %d hdr %d mtu%d\n",
+                                  skb->len, eth_hdr_len(skb->data), dev->mtu);
                        dev_kfree_skb_any(skb);
                        return NETDEV_TX_OK;
                }
@@ -1831,7 +1831,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
                if (skb->ip_summed == CHECKSUM_PARTIAL &&
                    ip_hdr(skb)->protocol == IPPROTO_UDP) {
                        if (unlikely(skb_checksum_help(skb))) {
-                               pr_debug("%s: unable to do udp checksum\n", dev->name);
+                               netdev_dbg(dev, "unable to do udp checksum\n");
                                dev_kfree_skb_any(skb);
                                return NETDEV_TX_OK;
                        }
index f15ee326d5c19414563b30abbb66ba780fd59b00..2b5e62193ceaace56320adadfac566f29f6984b1 100644 (file)
@@ -29,6 +29,9 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -153,7 +156,7 @@ struct workqueue_struct *cxgb3_wq;
 static void link_report(struct net_device *dev)
 {
        if (!netif_carrier_ok(dev))
-               printk(KERN_INFO "%s: link down\n", dev->name);
+               netdev_info(dev, "link down\n");
        else {
                const char *s = "10Mbps";
                const struct port_info *p = netdev_priv(dev);
@@ -170,8 +173,9 @@ static void link_report(struct net_device *dev)
                        break;
                }
 
-               printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
-                      p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+               netdev_info(dev, "link up, %s, %s-duplex\n",
+                           s, p->link_config.duplex == DUPLEX_FULL
+                           ? "full" : "half");
        }
 }
 
@@ -318,10 +322,10 @@ void t3_os_phymod_changed(struct adapter *adap, int port_id)
        const struct port_info *pi = netdev_priv(dev);
 
        if (pi->phy.modtype == phy_modtype_none)
-               printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
+               netdev_info(dev, "PHY module unplugged\n");
        else
-               printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
-                      mod_str[pi->phy.modtype]);
+               netdev_info(dev, "%s PHY module inserted\n",
+                           mod_str[pi->phy.modtype]);
 }
 
 static void cxgb_set_rxmode(struct net_device *dev)
@@ -1422,8 +1426,7 @@ static int cxgb_open(struct net_device *dev)
        if (is_offload(adapter) && !ofld_disable) {
                err = offload_open(dev);
                if (err)
-                       printk(KERN_WARNING
-                              "Could not initialize offload capabilities\n");
+                       pr_warn("Could not initialize offload capabilities\n");
        }
 
        netif_set_real_num_tx_queues(dev, pi->nqsets);
@@ -3132,14 +3135,13 @@ static void print_port_info(struct adapter *adap, const struct adapter_info *ai)
 
                if (!test_bit(i, &adap->registered_device_map))
                        continue;
-               printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
-                      dev->name, ai->desc, pi->phy.desc,
-                      is_offload(adap) ? "R" : "", adap->params.rev, buf,
-                      (adap->flags & USING_MSIX) ? " MSI-X" :
-                      (adap->flags & USING_MSI) ? " MSI" : "");
+               netdev_info(dev, "%s %s %sNIC (rev %d) %s%s\n",
+                           ai->desc, pi->phy.desc,
+                           is_offload(adap) ? "R" : "", adap->params.rev, buf,
+                           (adap->flags & USING_MSIX) ? " MSI-X" :
+                           (adap->flags & USING_MSI) ? " MSI" : "");
                if (adap->name == dev->name && adap->params.vpd.mclk)
-                       printk(KERN_INFO
-                              "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
+                       pr_info("%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
                               adap->name, t3_mc7_size(&adap->cm) >> 20,
                               t3_mc7_size(&adap->pmtx) >> 20,
                               t3_mc7_size(&adap->pmrx) >> 20,
@@ -3177,24 +3179,18 @@ static void cxgb3_init_iscsi_mac(struct net_device *dev)
                        NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
 static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       static int version_printed;
-
        int i, err, pci_using_dac = 0;
        resource_size_t mmio_start, mmio_len;
        const struct adapter_info *ai;
        struct adapter *adapter = NULL;
        struct port_info *pi;
 
-       if (!version_printed) {
-               printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
-               ++version_printed;
-       }
+       pr_info_once("%s - version %s\n", DRV_DESC, DRV_VERSION);
 
        if (!cxgb3_wq) {
                cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
                if (!cxgb3_wq) {
-                       printk(KERN_ERR DRV_NAME
-                              ": cannot initialize work queue\n");
+                       pr_err("cannot initialize work queue\n");
                        return -ENOMEM;
                }
        }
index 942dace361d229e061545c51340f9fb37d194dd7..4232767862b5857c33d324095e9d6ba1c2d0cc18 100644 (file)
@@ -30,6 +30,8 @@
  * SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <net/neighbour.h>
@@ -62,9 +64,8 @@ static const unsigned int MAX_ATIDS = 64 * 1024;
 static const unsigned int ATID_BASE = 0x10000;
 
 static void cxgb_neigh_update(struct neighbour *neigh);
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
-                         struct dst_entry *new, struct neighbour *new_neigh,
-                         const void *daddr);
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+                         struct neighbour *neigh, const void *daddr);
 
 static inline int offload_activated(struct t3cdev *tdev)
 {
@@ -182,14 +183,17 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
                struct net_device *dev = adapter->port[i];
 
                if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+                       rcu_read_lock();
                        if (vlan && vlan != VLAN_VID_MASK) {
-                               rcu_read_lock();
                                dev = __vlan_find_dev_deep(dev, vlan);
-                               rcu_read_unlock();
                        } else if (netif_is_bond_slave(dev)) {
-                               while (dev->master)
-                                       dev = dev->master;
+                               struct net_device *upper_dev;
+
+                               while ((upper_dev =
+                                       netdev_master_upper_dev_get_rcu(dev)))
+                                       dev = upper_dev;
                        }
+                       rcu_read_unlock();
                        return dev;
                }
        }
@@ -232,8 +236,7 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
                if ((val >> S_MAXRXDATA) != 0x3f60) {
                        val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE);
                        val |= V_MAXRXDATA(0x3f60);
-                       printk(KERN_INFO
-                               "%s, iscsi set MaxRxData to 16224 (0x%x).\n",
+                       pr_info("%s, iscsi set MaxRxData to 16224 (0x%x)\n",
                                adapter->name, val);
                        t3_write_reg(adapter, A_TP_PARA_REG2, val);
                }
@@ -253,8 +256,7 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
                for (i = 0; i < 4; i++)
                        val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i);
                if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) {
-                       printk(KERN_INFO
-                               "%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n",
+                       pr_info("%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u\n",
                                adapter->name, val, uiip->pgsz_factor[0],
                                uiip->pgsz_factor[1], uiip->pgsz_factor[2],
                                uiip->pgsz_factor[3]);
@@ -706,8 +708,7 @@ static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
        struct cpl_smt_write_rpl *rpl = cplhdr(skb);
 
        if (rpl->status != CPL_ERR_NONE)
-               printk(KERN_ERR
-                      "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+               pr_err("Unexpected SMT_WRITE_RPL status %u for entry %u\n",
                       rpl->status, GET_TID(rpl));
 
        return CPL_RET_BUF_DONE;
@@ -718,8 +719,7 @@ static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
        struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
 
        if (rpl->status != CPL_ERR_NONE)
-               printk(KERN_ERR
-                      "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+               pr_err("Unexpected L2T_WRITE_RPL status %u for entry %u\n",
                       rpl->status, GET_TID(rpl));
 
        return CPL_RET_BUF_DONE;
@@ -730,8 +730,7 @@ static int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
        struct cpl_rte_write_rpl *rpl = cplhdr(skb);
 
        if (rpl->status != CPL_ERR_NONE)
-               printk(KERN_ERR
-                      "Unexpected RTE_WRITE_RPL status %u for entry %u\n",
+               pr_err("Unexpected RTE_WRITE_RPL status %u for entry %u\n",
                       rpl->status, GET_TID(rpl));
 
        return CPL_RET_BUF_DONE;
@@ -751,7 +750,7 @@ static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
                                                                    t3c_tid->
                                                                    ctx);
        } else {
-               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+               pr_err("%s: received clientless CPL command 0x%x\n",
                       dev->name, CPL_ACT_OPEN_RPL);
                return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
        }
@@ -769,7 +768,7 @@ static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
                return t3c_tid->client->handlers[p->opcode] (dev, skb,
                                                             t3c_tid->ctx);
        } else {
-               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+               pr_err("%s: received clientless CPL command 0x%x\n",
                       dev->name, p->opcode);
                return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
        }
@@ -787,7 +786,7 @@ static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
                return t3c_tid->client->handlers[p->opcode]
                    (dev, skb, t3c_tid->ctx);
        } else {
-               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+               pr_err("%s: received clientless CPL command 0x%x\n",
                       dev->name, p->opcode);
                return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
        }
@@ -814,7 +813,7 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
                return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
                    (dev, skb, t3c_tid->ctx);
        } else {
-               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+               pr_err("%s: received clientless CPL command 0x%x\n",
                       dev->name, CPL_PASS_ACCEPT_REQ);
                return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
        }
@@ -908,7 +907,7 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
                return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
                    (dev, skb, t3c_tid->ctx);
        } else {
-               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+               pr_err("%s: received clientless CPL command 0x%x\n",
                       dev->name, CPL_ACT_ESTABLISH);
                return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
        }
@@ -954,7 +953,7 @@ static int do_term(struct t3cdev *dev, struct sk_buff *skb)
                return t3c_tid->client->handlers[opcode] (dev, skb,
                                                          t3c_tid->ctx);
        } else {
-               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+               pr_err("%s: received clientless CPL command 0x%x\n",
                       dev->name, opcode);
                return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
        }
@@ -970,10 +969,9 @@ static int nb_callback(struct notifier_block *self, unsigned long event,
        }
        case (NETEVENT_REDIRECT):{
                struct netevent_redirect *nr = ctx;
-               cxgb_redirect(nr->old, nr->old_neigh,
-                             nr->new, nr->new_neigh,
+               cxgb_redirect(nr->old, nr->new, nr->neigh,
                              nr->daddr);
-               cxgb_neigh_update(nr->new_neigh);
+               cxgb_neigh_update(nr->neigh);
                break;
        }
        default:
@@ -991,8 +989,7 @@ static struct notifier_block nb = {
  */
 static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
 {
-       printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
-              *skb->data);
+       pr_err("%s: received bad CPL command 0x%x\n", dev->name, *skb->data);
        return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 }
 
@@ -1010,8 +1007,8 @@ void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
        if (opcode < NUM_CPL_CMDS)
                cpl_handlers[opcode] = h ? h : do_bad_cpl;
        else
-               printk(KERN_ERR "T3C: handler registration for "
-                      "opcode %x failed\n", opcode);
+               pr_err("T3C: handler registration for opcode %x failed\n",
+                      opcode);
 }
 
 EXPORT_SYMBOL(t3_register_cpl_handler);
@@ -1030,9 +1027,8 @@ static int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
                if (ret & CPL_RET_UNKNOWN_TID) {
                        union opcode_tid *p = cplhdr(skb);
 
-                       printk(KERN_ERR "%s: CPL message (opcode %u) had "
-                              "unknown TID %u\n", dev->name, opcode,
-                              G_TID(ntohl(p->opcode_tid)));
+                       pr_err("%s: CPL message (opcode %u) had unknown TID %u\n",
+                              dev->name, opcode, G_TID(ntohl(p->opcode_tid)));
                }
 #endif
                if (ret & CPL_RET_BUF_DONE)
@@ -1096,7 +1092,7 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
 
        skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
        if (!skb) {
-               printk(KERN_ERR "%s: cannot allocate skb!\n", __func__);
+               pr_err("%s: cannot allocate skb!\n", __func__);
                return;
        }
        skb->priority = CPL_PRIORITY_CONTROL;
@@ -1111,11 +1107,11 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
        tdev->send(tdev, skb);
 }
 
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
-                         struct dst_entry *new, struct neighbour *new_neigh,
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+                         struct neighbour *neigh,
                          const void *daddr)
 {
-       struct net_device *olddev, *newdev;
+       struct net_device *dev;
        struct tid_info *ti;
        struct t3cdev *tdev;
        u32 tid;
@@ -1123,29 +1119,17 @@ static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
        struct l2t_entry *e;
        struct t3c_tid_entry *te;
 
-       olddev = old_neigh->dev;
-       newdev = new_neigh->dev;
+       dev = neigh->dev;
 
-       if (!is_offloading(olddev))
-               return;
-       if (!is_offloading(newdev)) {
-               printk(KERN_WARNING "%s: Redirect to non-offload "
-                      "device ignored.\n", __func__);
+       if (!is_offloading(dev))
                return;
-       }
-       tdev = dev2t3cdev(olddev);
+       tdev = dev2t3cdev(dev);
        BUG_ON(!tdev);
-       if (tdev != dev2t3cdev(newdev)) {
-               printk(KERN_WARNING "%s: Redirect to different "
-                      "offload device ignored.\n", __func__);
-               return;
-       }
 
        /* Add new L2T entry */
-       e = t3_l2t_get(tdev, new, newdev, daddr);
+       e = t3_l2t_get(tdev, new, dev, daddr);
        if (!e) {
-               printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
-                      __func__);
+               pr_err("%s: couldn't allocate new l2t entry!\n", __func__);
                return;
        }
 
index dd901c5061b910a607f54105d99eef7ea1690f49..9096dc09c72f1c1ad16cdfa27a3d283f6c33fea6 100644 (file)
@@ -1278,7 +1278,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        /* update port statistics */
-       if (skb->ip_summed == CHECKSUM_COMPLETE)
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
                qs->port_stats[SGE_PSTAT_TX_CSUM]++;
        if (skb_shinfo(skb)->gso_size)
                qs->port_stats[SGE_PSTAT_TSO]++;
index 3dee68612c9e87868e3b5b61b475693273480319..c74a898fcd4f7c41bd338ba08fa8e73b078ff5db 100644 (file)
@@ -3725,8 +3725,6 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
 
                memcpy(adapter->port[i]->dev_addr, hw_addr,
                       ETH_ALEN);
-               memcpy(adapter->port[i]->perm_addr, hw_addr,
-                      ETH_ALEN);
                init_link_config(&p->link_config, p->phy.caps);
                p->phy.ops->power_down(&p->phy, 1);
 
index c306df7d45684ce1fcd2f25012e8100da98abdd2..c6c05bfef0e019b42324fcd7164d7d4c67da96e4 100644 (file)
@@ -4027,8 +4027,7 @@ static int adap_init0_no_config(struct adapter *adapter, int reset)
                                                  VFRES_NEQ, VFRES_NETHCTRL,
                                                  VFRES_NIQFLINT, VFRES_NIQ,
                                                  VFRES_TC, VFRES_NVI,
-                                                 FW_PFVF_CMD_CMASK_GET(
-                                                 FW_PFVF_CMD_CMASK_MASK),
+                                                 FW_PFVF_CMD_CMASK_MASK,
                                                  pfvfres_pmask(
                                                  adapter, pf, vf),
                                                  VFRES_NEXACTF,
@@ -5142,7 +5141,7 @@ static int __init cxgb4_init_module(void)
        /* Debugfs support is optional, just warn if this fails */
        cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
        if (!cxgb4_debugfs_root)
-               pr_warning("could not create debugfs entry, continuing\n");
+               pr_warn("could not create debugfs entry, continuing\n");
 
        ret = pci_register_driver(&cxgb4_driver);
        if (ret < 0)
index 22f3af5166bf50ec7d2c6b7d2bd8778b6e15e963..4ce62031f62fa3a51500d8a571feba701e2fa6ed 100644 (file)
@@ -3603,7 +3603,6 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
                p->lport = j;
                p->rss_size = rss_size;
                memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
-               memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN);
                adap->port[i]->dev_id = j;
 
                ret = ntohl(c.u.info.lstatus_to_modtype);
index 611396c4b3810020264b638523566c3a8a48aba6..68eaa9c88c7d8a77646bd217e00877a281254a59 100644 (file)
@@ -466,7 +466,6 @@ static inline void t4_os_set_hw_addr(struct adapter *adapter, int pidx,
                                     u8 hw_addr[])
 {
        memcpy(adapter->port[pidx]->dev_addr, hw_addr, ETH_ALEN);
-       memcpy(adapter->port[pidx]->perm_addr, hw_addr, ETH_ALEN);
 }
 
 /**
index 0188df705719d8d601c6d4dd4685f1f762c023f6..56b46ab2d4c5ae452410da4469ab7b2c86ba1894 100644 (file)
@@ -33,6 +33,8 @@
  * SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -196,11 +198,10 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)
                        break;
                }
 
-               printk(KERN_INFO "%s: link up, %s, full-duplex, %s PAUSE\n",
-                      dev->name, s, fc);
+               netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, fc);
        } else {
                netif_carrier_off(dev);
-               printk(KERN_INFO "%s: link down\n", dev->name);
+               netdev_info(dev, "link down\n");
        }
 }
 
@@ -2465,8 +2466,6 @@ static const struct net_device_ops cxgb4vf_netdev_ops     = {
 static int cxgb4vf_pci_probe(struct pci_dev *pdev,
                             const struct pci_device_id *ent)
 {
-       static int version_printed;
-
        int pci_using_dac;
        int err, pidx;
        unsigned int pmask;
@@ -2478,10 +2477,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
         * Print our driver banner the first time we're called to initialize a
         * device.
         */
-       if (version_printed == 0) {
-               printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
-               version_printed = 1;
-       }
+       pr_info_once("%s - version %s\n", DRV_DESC, DRV_VERSION);
 
        /*
         * Initialize generic PCI device state.
@@ -2920,18 +2916,15 @@ static int __init cxgb4vf_module_init(void)
         * Vet our module parameters.
         */
        if (msi != MSI_MSIX && msi != MSI_MSI) {
-               printk(KERN_WARNING KBUILD_MODNAME
-                      ": bad module parameter msi=%d; must be %d"
-                      " (MSI-X or MSI) or %d (MSI)\n",
-                      msi, MSI_MSIX, MSI_MSI);
+               pr_warn("bad module parameter msi=%d; must be %d (MSI-X or MSI) or %d (MSI)\n",
+                       msi, MSI_MSIX, MSI_MSI);
                return -EINVAL;
        }
 
        /* Debugfs support is optional, just warn if this fails */
        cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
        if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
-               printk(KERN_WARNING KBUILD_MODNAME ": could not create"
-                      " debugfs entry, continuing\n");
+               pr_warn("could not create debugfs entry, continuing\n");
 
        ret = pci_register_driver(&cxgb4vf_driver);
        if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
index 78c55213eaf7c59e9a865fc48942c112a6e2f7c0..354cbb78ed507876c3f7c54f735e2791a4a6d32a 100644 (file)
@@ -710,8 +710,8 @@ static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 64866ff1aea0d9894f2a296ebed80324e5638f15..ec1a233622c6ae704f9b37bb4a2f4805d2860b1a 100644 (file)
@@ -865,7 +865,6 @@ static int enic_set_mac_addr(struct net_device *netdev, char *addr)
        }
 
        memcpy(netdev->dev_addr, addr, netdev->addr_len);
-       netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
        return 0;
 }
@@ -1491,7 +1490,8 @@ static int enic_request_intr(struct enic *enic)
 
                for (i = 0; i < enic->rq_count; i++) {
                        intr = enic_msix_rq_intr(enic, i);
-                       sprintf(enic->msix[intr].devname,
+                       snprintf(enic->msix[intr].devname,
+                               sizeof(enic->msix[intr].devname),
                                "%.11s-rx-%d", netdev->name, i);
                        enic->msix[intr].isr = enic_isr_msix_rq;
                        enic->msix[intr].devid = &enic->napi[i];
@@ -1499,20 +1499,23 @@ static int enic_request_intr(struct enic *enic)
 
                for (i = 0; i < enic->wq_count; i++) {
                        intr = enic_msix_wq_intr(enic, i);
-                       sprintf(enic->msix[intr].devname,
+                       snprintf(enic->msix[intr].devname,
+                               sizeof(enic->msix[intr].devname),
                                "%.11s-tx-%d", netdev->name, i);
                        enic->msix[intr].isr = enic_isr_msix_wq;
                        enic->msix[intr].devid = enic;
                }
 
                intr = enic_msix_err_intr(enic);
-               sprintf(enic->msix[intr].devname,
+               snprintf(enic->msix[intr].devname,
+                       sizeof(enic->msix[intr].devname),
                        "%.11s-err", netdev->name);
                enic->msix[intr].isr = enic_isr_msix_err;
                enic->msix[intr].devid = enic;
 
                intr = enic_msix_notify_intr(enic);
-               sprintf(enic->msix[intr].devname,
+               snprintf(enic->msix[intr].devname,
+                       sizeof(enic->msix[intr].devname),
                        "%.11s-notify", netdev->name);
                enic->msix[intr].isr = enic_isr_msix_notify;
                enic->msix[intr].devid = enic;
index c73472c369cd6e7334e42baf3d61f15952ece55a..8cdf02503d13d5bdd52348f77995c0ce47618f1c 100644 (file)
@@ -434,9 +434,10 @@ static void dm9000_get_drvinfo(struct net_device *dev,
 {
        board_info_t *dm = to_dm9000_board(dev);
 
-       strcpy(info->driver, CARDNAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, to_platform_device(dm->dev)->name);
+       strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, to_platform_device(dm->dev)->name,
+               sizeof(info->bus_info));
 }
 
 static u32 dm9000_get_msglevel(struct net_device *dev)
index 37940279ded82e7ace413b06c62068de8ea7dd48..68262aa57d017eb2d2e3b00623503a55005d6649 100644 (file)
@@ -17,21 +17,5 @@ config NET_VENDOR_DEC
          your specific card in the following questions.
 
 if NET_VENDOR_DEC
-
-config EWRK3
-       tristate "EtherWORKS 3 (DE203, DE204, DE205) support"
-       depends on ISA
-       select CRC32
-       ---help---
-         This driver supports the DE203, DE204 and DE205 network (Ethernet)
-         cards. If this is for you, say Y and read
-         <file:Documentation/networking/ewrk3.txt> in the kernel source as
-         well as the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called ewrk3.
-
 source "drivers/net/ethernet/dec/tulip/Kconfig"
-
 endif # NET_VENDOR_DEC
index 1b01ed8d42c85ed95f2e41b0e80e4b2ef3929273..32993fccbbfd8dc3aeb884da6e9d1b6b3e35153f 100644 (file)
@@ -2,5 +2,4 @@
 # Makefile for the Digital Equipment Inc. network device drivers.
 #
 
-obj-$(CONFIG_EWRK3) += ewrk3.o
 obj-$(CONFIG_NET_TULIP) += tulip/
diff --git a/drivers/net/ethernet/dec/ewrk3.c b/drivers/net/ethernet/dec/ewrk3.c
deleted file mode 100644 (file)
index 9f992b9..0000000
+++ /dev/null
@@ -1,1961 +0,0 @@
-/*  ewrk3.c: A DIGITAL EtherWORKS 3 ethernet driver for Linux.
-
-   Written 1994 by David C. Davies.
-
-   Copyright 1994 Digital Equipment Corporation.
-
-   This software may be used and distributed according to the terms of
-   the GNU General Public License, incorporated herein by reference.
-
-   This driver is written for the Digital Equipment Corporation series
-   of EtherWORKS ethernet cards:
-
-   DE203 Turbo (BNC)
-   DE204 Turbo (TP)
-   DE205 Turbo (TP BNC)
-
-   The driver has been tested on a relatively busy  network using the DE205
-   card and benchmarked with 'ttcp': it transferred 16M  of data at 975kB/s
-   (7.8Mb/s) to a DECstation 5000/200.
-
-   The author may be reached at davies@maniac.ultranet.com.
-
-   =========================================================================
-   This driver has been written  substantially  from scratch, although  its
-   inheritance of style and stack interface from 'depca.c' and in turn from
-   Donald Becker's 'lance.c' should be obvious.
-
-   The  DE203/4/5 boards  all  use a new proprietary   chip in place of the
-   LANCE chip used in prior cards  (DEPCA, DE100, DE200/1/2, DE210, DE422).
-   Use the depca.c driver in the standard distribution  for the LANCE based
-   cards from DIGITAL; this driver will not work with them.
-
-   The DE203/4/5 cards have 2  main modes: shared memory  and I/O only. I/O
-   only makes  all the card accesses through  I/O transactions and  no high
-   (shared)  memory is used. This  mode provides a >48% performance penalty
-   and  is deprecated in this  driver,  although allowed to provide initial
-   setup when hardstrapped.
-
-   The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is
-   no point in using any mode other than the 2kB  mode - their performances
-   are virtually identical, although the driver has  been tested in the 2kB
-   and 32kB modes. I would suggest you uncomment the line:
-
-   FORCE_2K_MODE;
-
-   to allow the driver to configure the card as a  2kB card at your current
-   base  address, thus leaving more  room to clutter  your  system box with
-   other memory hungry boards.
-
-   As many ISA  and EISA cards  can be supported  under this driver  as you
-   wish, limited primarily  by the available IRQ lines,  rather than by the
-   available I/O addresses  (24 ISA,  16 EISA).   I have  checked different
-   configurations of  multiple  depca cards and  ewrk3 cards  and have  not
-   found a problem yet (provided you have at least depca.c v0.38) ...
-
-   The board IRQ setting   must be at  an unused  IRQ which is  auto-probed
-   using  Donald  Becker's autoprobe  routines.   All  these cards   are at
-   {5,10,11,15}.
-
-   No 16MB memory  limitation should exist with this  driver as DMA is  not
-   used and the common memory area is in low memory on the network card (my
-   current system has 20MB and I've not had problems yet).
-
-   The ability to load  this driver as a  loadable module has been included
-   and used  extensively during the  driver development (to save those long
-   reboot sequences). To utilise this ability, you have to do 8 things:
-
-   0) have a copy of the loadable modules code installed on your system.
-   1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
-   temporary directory.
-   2) edit the  source code near  line 1898 to reflect  the I/O address and
-   IRQ you're using.
-   3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
-   that the correct bits are compiled (see end of source code).
-   4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
-   kernel with the ewrk3 configuration turned off and reboot.
-   5) insmod ewrk3.o
-   [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
-   [Adam Kropelin: now accepts irq=x1,x2 io=y1,y2 for multiple cards]
-   6) run the net startup bits for your new eth?? interface manually
-   (usually /etc/rc.inet[12] at boot time).
-   7) enjoy!
-
-   Note that autoprobing is not allowed in loadable modules - the system is
-   already up and running and you're messing with interrupts.
-
-   To unload a module, turn off the associated interface
-   'ifconfig eth?? down' then 'rmmod ewrk3'.
-
-   Promiscuous   mode has been  turned  off  in this driver,   but  all the
-   multicast  address bits  have been   turned on. This  improved the  send
-   performance on a busy network by about 13%.
-
-   Ioctl's have now been provided (primarily because  I wanted to grab some
-   packet size statistics). They  are patterned after 'plipconfig.c' from a
-   suggestion by Alan Cox.  Using these  ioctls, you can enable promiscuous
-   mode, add/delete multicast  addresses, change the hardware address,  get
-   packet size distribution statistics and muck around with the control and
-   status register. I'll add others if and when the need arises.
-
-   TO DO:
-   ------
-
-
-   Revision History
-   ----------------
-
-   Version   Date        Description
-
-   0.1     26-aug-94   Initial writing. ALPHA code release.
-   0.11    31-aug-94   Fixed: 2k mode memory base calc.,
-   LeMAC version calc.,
-   IRQ vector assignments during autoprobe.
-   0.12    31-aug-94   Tested working on LeMAC2 (DE20[345]-AC) card.
-   Fixed up MCA hash table algorithm.
-   0.20     4-sep-94   Added IOCTL functionality.
-   0.21    14-sep-94   Added I/O mode.
-   0.21axp 15-sep-94   Special version for ALPHA AXP Linux V1.0.
-   0.22    16-sep-94   Added more IOCTLs & tidied up.
-   0.23    21-sep-94   Added transmit cut through.
-   0.24    31-oct-94   Added uid checks in some ioctls.
-   0.30     1-nov-94   BETA code release.
-   0.31     5-dec-94   Added check/allocate region code.
-   0.32    16-jan-95   Broadcast packet fix.
-   0.33    10-Feb-95   Fix recognition bug reported by <bkm@star.rl.ac.uk>.
-   0.40    27-Dec-95   Rationalise MODULE and autoprobe code.
-   Rewrite for portability & updated.
-   ALPHA support from <jestabro@amt.tay1.dec.com>
-   Added verify_area() calls in ewrk3_ioctl() from
-   suggestion by <heiko@colossus.escape.de>.
-   Add new multicasting code.
-   0.41    20-Jan-96   Fix IRQ set up problem reported by
-   <kenneth@bbs.sas.ntu.ac.sg>.
-   0.42    22-Apr-96   Fix alloc_device() bug <jari@markkus2.fimr.fi>
-   0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
-   0.44    08-Nov-01   use library crc32 functions <Matt_Domsch@dell.com>
-   0.45    19-Jul-02   fix unaligned access on alpha <martin@bruli.net>
-   0.46    10-Oct-02   Multiple NIC support when module <akropel1@rochester.rr.com>
-   0.47    18-Oct-02   ethtool support <akropel1@rochester.rr.com>
-   0.48    18-Oct-02   cli/sti removal for 2.5 <vda@port.imtp.ilyichevsk.odessa.ua>
-   ioctl locking, signature search cleanup <akropel1@rochester.rr.com>
-
-   =========================================================================
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "ewrk3.h"
-
-#define DRV_NAME       "ewrk3"
-#define DRV_VERSION    "0.48"
-
-static char version[] __initdata =
-DRV_NAME ":v" DRV_VERSION " 2002/10/18 davies@maniac.ultranet.com\n";
-
-#ifdef EWRK3_DEBUG
-static int ewrk3_debug = EWRK3_DEBUG;
-#else
-static int ewrk3_debug = 1;
-#endif
-
-#define EWRK3_NDA 0xffe0       /* No Device Address */
-
-#define PROBE_LENGTH    32
-#define ETH_PROM_SIG    0xAA5500FFUL
-
-#ifndef EWRK3_SIGNATURE
-#define EWRK3_SIGNATURE {"DE203","DE204","DE205",""}
-#define EWRK3_STRLEN 8
-#endif
-
-#ifndef EWRK3_RAM_BASE_ADDRESSES
-#define EWRK3_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0x00000}
-#endif
-
-/*
-   ** Sets up the I/O area for the autoprobe.
- */
-#define EWRK3_IO_BASE 0x100    /* Start address for probe search */
-#define EWRK3_IOP_INC 0x20     /* I/O address increment */
-#define EWRK3_TOTAL_SIZE 0x20  /* required I/O address length */
-
-#ifndef MAX_NUM_EWRK3S
-#define MAX_NUM_EWRK3S 21
-#endif
-
-#ifndef EWRK3_EISA_IO_PORTS
-#define EWRK3_EISA_IO_PORTS 0x0c00     /* I/O port base address, slot 0 */
-#endif
-
-#ifndef MAX_EISA_SLOTS
-#define MAX_EISA_SLOTS 16
-#define EISA_SLOT_INC 0x1000
-#endif
-
-#define QUEUE_PKT_TIMEOUT (1*HZ)       /* Jiffies */
-
-/*
-   ** EtherWORKS 3 shared memory window sizes
- */
-#define IO_ONLY         0x00
-#define SHMEM_2K        0x800
-#define SHMEM_32K       0x8000
-#define SHMEM_64K       0x10000
-
-/*
-   ** EtherWORKS 3 IRQ ENABLE/DISABLE
- */
-#define ENABLE_IRQs { \
-  icr |= lp->irq_mask;\
-  outb(icr, EWRK3_ICR);                     /* Enable the IRQs */\
-}
-
-#define DISABLE_IRQs { \
-  icr = inb(EWRK3_ICR);\
-  icr &= ~lp->irq_mask;\
-  outb(icr, EWRK3_ICR);                     /* Disable the IRQs */\
-}
-
-/*
-   ** EtherWORKS 3 START/STOP
- */
-#define START_EWRK3 { \
-  csr = inb(EWRK3_CSR);\
-  csr &= ~(CSR_TXD|CSR_RXD);\
-  outb(csr, EWRK3_CSR);                     /* Enable the TX and/or RX */\
-}
-
-#define STOP_EWRK3 { \
-  csr = (CSR_TXD|CSR_RXD);\
-  outb(csr, EWRK3_CSR);                     /* Disable the TX and/or RX */\
-}
-
-/*
-   ** The EtherWORKS 3 private structure
- */
-#define EWRK3_PKT_STAT_SZ 16
-#define EWRK3_PKT_BIN_SZ  128  /* Should be >=100 unless you
-                                  increase EWRK3_PKT_STAT_SZ */
-
-struct ewrk3_stats {
-       u32 bins[EWRK3_PKT_STAT_SZ];
-       u32 unicast;
-       u32 multicast;
-       u32 broadcast;
-       u32 excessive_collisions;
-       u32 tx_underruns;
-       u32 excessive_underruns;
-};
-
-struct ewrk3_private {
-       char adapter_name[80];  /* Name exported to /proc/ioports */
-       u_long shmem_base;      /* Shared memory start address */
-       void __iomem *shmem;
-       u_long shmem_length;    /* Shared memory window length */
-       struct ewrk3_stats pktStats; /* Private stats counters */
-       u_char irq_mask;        /* Adapter IRQ mask bits */
-       u_char mPage;           /* Maximum 2kB Page number */
-       u_char lemac;           /* Chip rev. level */
-       u_char hard_strapped;   /* Don't allow a full open */
-       u_char txc;             /* Transmit cut through */
-       void __iomem *mctbl;    /* Pointer to the multicast table */
-       u_char led_mask;        /* Used to reserve LED access for ethtool */
-       spinlock_t hw_lock;
-};
-
-/*
-   ** Force the EtherWORKS 3 card to be in 2kB MODE
- */
-#define FORCE_2K_MODE { \
-  shmem_length = SHMEM_2K;\
-  outb(((mem_start - 0x80000) >> 11), EWRK3_MBR);\
-}
-
-/*
-   ** Public Functions
- */
-static int ewrk3_open(struct net_device *dev);
-static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
-static int ewrk3_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops ethtool_ops_203;
-static const struct ethtool_ops ethtool_ops;
-
-/*
-   ** Private functions
- */
-static int ewrk3_hw_init(struct net_device *dev, u_long iobase);
-static void ewrk3_init(struct net_device *dev);
-static int ewrk3_rx(struct net_device *dev);
-static int ewrk3_tx(struct net_device *dev);
-static void ewrk3_timeout(struct net_device *dev);
-
-static void EthwrkSignature(char *name, char *eeprom_image);
-static int DevicePresent(u_long iobase);
-static void SetMulticastFilter(struct net_device *dev);
-static int EISA_signature(char *name, s32 eisa_id);
-
-static int Read_EEPROM(u_long iobase, u_char eaddr);
-static int Write_EEPROM(short data, u_long iobase, u_char eaddr);
-static u_char get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType);
-
-static int ewrk3_probe1(struct net_device *dev, u_long iobase, int irq);
-static int isa_probe(struct net_device *dev, u_long iobase);
-static int eisa_probe(struct net_device *dev, u_long iobase);
-
-static u_char irq[MAX_NUM_EWRK3S+1] = {5, 0, 10, 3, 11, 9, 15, 12};
-
-static char name[EWRK3_STRLEN + 1];
-static int num_ewrks3s;
-
-/*
-   ** Miscellaneous defines...
- */
-#define INIT_EWRK3 {\
-    outb(EEPROM_INIT, EWRK3_IOPR);\
-    mdelay(1);\
-}
-
-#ifndef MODULE
-struct net_device * __init ewrk3_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-
-}
-#endif
-
-static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq)
-{
-       int err;
-
-       dev->base_addr = iobase;
-       dev->irq = irq;
-
-       /* Address PROM pattern */
-       err = isa_probe(dev, iobase);
-       if (err != 0)
-               err = eisa_probe(dev, iobase);
-
-       if (err)
-               return err;
-
-       err = register_netdev(dev);
-       if (err)
-               release_region(dev->base_addr, EWRK3_TOTAL_SIZE);
-
-       return err;
-}
-
-static const struct net_device_ops ewrk3_netdev_ops = {
-       .ndo_open               = ewrk3_open,
-       .ndo_start_xmit         = ewrk3_queue_pkt,
-       .ndo_stop               = ewrk3_close,
-       .ndo_set_rx_mode        = set_multicast_list,
-       .ndo_do_ioctl           = ewrk3_ioctl,
-       .ndo_tx_timeout         = ewrk3_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init
-ewrk3_hw_init(struct net_device *dev, u_long iobase)
-{
-       struct ewrk3_private *lp;
-       int i, status = 0;
-       u_long mem_start, shmem_length;
-       u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
-       u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
-
-       /*
-       ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
-       ** This also disables the EISA_ENABLE bit in the EISA Control Register.
-        */
-       if (iobase > 0x400)
-               eisa_cr = inb(EISA_CR);
-       INIT_EWRK3;
-
-       nicsr = inb(EWRK3_CSR);
-
-       icr = inb(EWRK3_ICR);
-       icr &= 0x70;
-       outb(icr, EWRK3_ICR);   /* Disable all the IRQs */
-
-       if (nicsr != (CSR_TXD | CSR_RXD))
-               return -ENXIO;
-
-       /* Check that the EEPROM is alive and well and not living on Pluto... */
-       for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) {
-               union {
-                       short val;
-                       char c[2];
-               } tmp;
-
-               tmp.val = (short) Read_EEPROM(iobase, (i >> 1));
-               eeprom_image[i] = tmp.c[0];
-               eeprom_image[i + 1] = tmp.c[1];
-               chksum += eeprom_image[i] + eeprom_image[i + 1];
-       }
-
-       if (chksum != 0) {      /* Bad EEPROM Data! */
-               printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
-               return -ENXIO;
-       }
-
-       EthwrkSignature(name, eeprom_image);
-       if (*name == '\0')
-               return -ENXIO;
-
-       dev->base_addr = iobase;
-
-       if (iobase > 0x400) {
-               outb(eisa_cr, EISA_CR);         /* Rewrite the EISA CR */
-       }
-       lemac = eeprom_image[EEPROM_CHIPVER];
-       cmr = inb(EWRK3_CMR);
-
-       if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) ||
-           ((lemac == LeMAC2) && !(cmr & CMR_HS))) {
-               printk("%s: %s at %#4lx", dev->name, name, iobase);
-               hard_strapped = 1;
-       } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) {
-               /* EISA slot address */
-               printk("%s: %s at %#4lx (EISA slot %ld)",
-                      dev->name, name, iobase, ((iobase >> 12) & 0x0f));
-       } else {        /* ISA port address */
-               printk("%s: %s at %#4lx", dev->name, name, iobase);
-       }
-
-       printk(", h/w address ");
-       if (lemac != LeMAC2)
-               DevicePresent(iobase);  /* need after EWRK3_INIT */
-       status = get_hw_addr(dev, eeprom_image, lemac);
-       printk("%pM\n", dev->dev_addr);
-
-       if (status) {
-               printk("      which has an EEPROM CRC error.\n");
-               return -ENXIO;
-       }
-
-       if (lemac == LeMAC2) {  /* Special LeMAC2 CMR things */
-               cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS);
-               if (eeprom_image[EEPROM_MISC0] & READ_AHEAD)
-                       cmr |= CMR_RA;
-               if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND)
-                       cmr |= CMR_WB;
-               if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL)
-                       cmr |= CMR_POLARITY;
-               if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK)
-                       cmr |= CMR_LINK;
-               if (eeprom_image[EEPROM_MISC0] & _0WS_ENA)
-                       cmr |= CMR_0WS;
-       }
-       if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM)
-               cmr |= CMR_DRAM;
-       outb(cmr, EWRK3_CMR);
-
-       cr = inb(EWRK3_CR);     /* Set up the Control Register */
-       cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
-       if (cr & SETUP_APD)
-               cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS;
-       cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS;
-       cr |= eeprom_image[EEPROM_MISC0] & ENA_16;
-       outb(cr, EWRK3_CR);
-
-       /*
-       ** Determine the base address and window length for the EWRK3
-       ** RAM from the memory base register.
-       */
-       mem_start = inb(EWRK3_MBR);
-       shmem_length = 0;
-       if (mem_start != 0) {
-               if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) {
-                       mem_start *= SHMEM_64K;
-                       shmem_length = SHMEM_64K;
-               } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) {
-                       mem_start *= SHMEM_32K;
-                       shmem_length = SHMEM_32K;
-               } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) {
-                       mem_start = mem_start * SHMEM_2K + 0x80000;
-                       shmem_length = SHMEM_2K;
-               } else {
-                       return -ENXIO;
-               }
-       }
-       /*
-       ** See the top of this source code for comments about
-       ** uncommenting this line.
-       */
-/*          FORCE_2K_MODE; */
-
-       if (hard_strapped) {
-               printk("      is hard strapped.\n");
-       } else if (mem_start) {
-               printk("      has a %dk RAM window", (int) (shmem_length >> 10));
-               printk(" at 0x%.5lx", mem_start);
-       } else {
-               printk("      is in I/O only mode");
-       }
-
-       lp = netdev_priv(dev);
-       lp->shmem_base = mem_start;
-       lp->shmem = ioremap(mem_start, shmem_length);
-       if (!lp->shmem)
-               return -ENOMEM;
-       lp->shmem_length = shmem_length;
-       lp->lemac = lemac;
-       lp->hard_strapped = hard_strapped;
-       lp->led_mask = CR_LED;
-       spin_lock_init(&lp->hw_lock);
-
-       lp->mPage = 64;
-       if (cmr & CMR_DRAM)
-               lp->mPage <<= 1;        /* 2 DRAMS on module */
-
-       sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
-
-       lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM;
-
-       if (!hard_strapped) {
-               /*
-               ** Enable EWRK3 board interrupts for autoprobing
-               */
-               icr |= ICR_IE;  /* Enable interrupts */
-               outb(icr, EWRK3_ICR);
-
-               /* The DMA channel may be passed in on this parameter. */
-               dev->dma = 0;
-
-               /* To auto-IRQ we enable the initialization-done and DMA err,
-                  interrupts. For now we will always get a DMA error. */
-               if (dev->irq < 2) {
-#ifndef MODULE
-                       u_char irqnum;
-                       unsigned long irq_mask;
-
-
-                       irq_mask = probe_irq_on();
-
-                       /*
-                       ** Trigger a TNE interrupt.
-                       */
-                       icr |= ICR_TNEM;
-                       outb(1, EWRK3_TDQ);     /* Write to the TX done queue */
-                       outb(icr, EWRK3_ICR);   /* Unmask the TXD interrupt */
-
-                       irqnum = irq[((icr & IRQ_SEL) >> 4)];
-
-                       mdelay(20);
-                       dev->irq = probe_irq_off(irq_mask);
-                       if ((dev->irq) && (irqnum == dev->irq)) {
-                               printk(" and uses IRQ%d.\n", dev->irq);
-                       } else {
-                               if (!dev->irq) {
-                                       printk(" and failed to detect IRQ line.\n");
-                               } else if ((irqnum == 1) && (lemac == LeMAC2)) {
-                                       printk(" and an illegal IRQ line detected.\n");
-                               } else {
-                                       printk(", but incorrect IRQ line detected.\n");
-                               }
-                               iounmap(lp->shmem);
-                               return -ENXIO;
-                       }
-
-                       DISABLE_IRQs;   /* Mask all interrupts */
-
-#endif                         /* MODULE */
-               } else {
-                       printk(" and requires IRQ%d.\n", dev->irq);
-               }
-       }
-
-       if (ewrk3_debug > 1) {
-               printk(version);
-       }
-       /* The EWRK3-specific entries in the device structure. */
-       dev->netdev_ops = &ewrk3_netdev_ops;
-       if (lp->adapter_name[4] == '3')
-               SET_ETHTOOL_OPS(dev, &ethtool_ops_203);
-       else
-               SET_ETHTOOL_OPS(dev, &ethtool_ops);
-       dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
-
-       dev->mem_start = 0;
-
-       return 0;
-}
-
-
-static int ewrk3_open(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_long iobase = dev->base_addr;
-       int status = 0;
-       u_char icr, csr;
-
-       /*
-          ** Stop the TX and RX...
-        */
-       STOP_EWRK3;
-
-       if (!lp->hard_strapped) {
-               if (request_irq(dev->irq, (void *) ewrk3_interrupt, 0, "ewrk3", dev)) {
-                       printk("ewrk3_open(): Requested IRQ%d is busy\n", dev->irq);
-                       status = -EAGAIN;
-               } else {
-
-                       /*
-                          ** Re-initialize the EWRK3...
-                        */
-                       ewrk3_init(dev);
-
-                       if (ewrk3_debug > 1) {
-                               printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);
-                               printk("  physical address: %pM\n", dev->dev_addr);
-                               if (lp->shmem_length == 0) {
-                                       printk("  no shared memory, I/O only mode\n");
-                               } else {
-                                       printk("  start of shared memory: 0x%08lx\n", lp->shmem_base);
-                                       printk("  window length: 0x%04lx\n", lp->shmem_length);
-                               }
-                               printk("  # of DRAMS: %d\n", ((inb(EWRK3_CMR) & 0x02) ? 2 : 1));
-                               printk("  csr:  0x%02x\n", inb(EWRK3_CSR));
-                               printk("  cr:   0x%02x\n", inb(EWRK3_CR));
-                               printk("  icr:  0x%02x\n", inb(EWRK3_ICR));
-                               printk("  cmr:  0x%02x\n", inb(EWRK3_CMR));
-                               printk("  fmqc: 0x%02x\n", inb(EWRK3_FMQC));
-                       }
-                       netif_start_queue(dev);
-                       /*
-                          ** Unmask EWRK3 board interrupts
-                        */
-                       icr = inb(EWRK3_ICR);
-                       ENABLE_IRQs;
-
-               }
-       } else {
-               printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name);
-               printk(KERN_ERR "      Run the 'ewrk3setup' utility or remove the hard straps.\n");
-               return -EINVAL;
-       }
-
-       return status;
-}
-
-/*
-   ** Initialize the EtherWORKS 3 operating conditions
- */
-static void ewrk3_init(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_char csr, page;
-       u_long iobase = dev->base_addr;
-       int i;
-
-       /*
-          ** Enable any multicasts
-        */
-       set_multicast_list(dev);
-
-       /*
-       ** Set hardware MAC address. Address is initialized from the EEPROM
-       ** during startup but may have since been changed by the user.
-       */
-       for (i=0; i<ETH_ALEN; i++)
-               outb(dev->dev_addr[i], EWRK3_PAR0 + i);
-
-       /*
-          ** Clean out any remaining entries in all the queues here
-        */
-       while (inb(EWRK3_TQ));
-       while (inb(EWRK3_TDQ));
-       while (inb(EWRK3_RQ));
-       while (inb(EWRK3_FMQ));
-
-       /*
-          ** Write a clean free memory queue
-        */
-       for (page = 1; page < lp->mPage; page++) {      /* Write the free page numbers */
-               outb(page, EWRK3_FMQ);  /* to the Free Memory Queue */
-       }
-
-       START_EWRK3;            /* Enable the TX and/or RX */
-}
-
-/*
- *  Transmit timeout
- */
-
-static void ewrk3_timeout(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_char icr, csr;
-       u_long iobase = dev->base_addr;
-
-       if (!lp->hard_strapped)
-       {
-               printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
-                      dev->name, inb(EWRK3_CSR));
-
-               /*
-                  ** Mask all board interrupts
-                */
-               DISABLE_IRQs;
-
-               /*
-                  ** Stop the TX and RX...
-                */
-               STOP_EWRK3;
-
-               ewrk3_init(dev);
-
-               /*
-                  ** Unmask EWRK3 board interrupts
-                */
-               ENABLE_IRQs;
-
-               dev->trans_start = jiffies; /* prevent tx timeout */
-               netif_wake_queue(dev);
-       }
-}
-
-/*
-   ** Writes a socket buffer to the free page queue
- */
-static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_long iobase = dev->base_addr;
-       void __iomem *buf = NULL;
-       u_char icr;
-       u_char page;
-
-       spin_lock_irq (&lp->hw_lock);
-       DISABLE_IRQs;
-
-       /* if no resources available, exit, request packet be queued */
-       if (inb (EWRK3_FMQC) == 0) {
-               printk (KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n",
-                       dev->name);
-               printk (KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",
-                       dev->name, inb (EWRK3_CSR), inb (EWRK3_ICR),
-                       inb (EWRK3_FMQC));
-               goto err_out;
-       }
-
-       /*
-        ** Get a free page from the FMQ
-        */
-       if ((page = inb (EWRK3_FMQ)) >= lp->mPage) {
-               printk ("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
-                    (u_char) page);
-               goto err_out;
-       }
-
-
-       /*
-        ** Set up shared memory window and pointer into the window
-        */
-       if (lp->shmem_length == IO_ONLY) {
-               outb (page, EWRK3_IOPR);
-       } else if (lp->shmem_length == SHMEM_2K) {
-               buf = lp->shmem;
-               outb (page, EWRK3_MPR);
-       } else if (lp->shmem_length == SHMEM_32K) {
-               buf = (((short) page << 11) & 0x7800) + lp->shmem;
-               outb ((page >> 4), EWRK3_MPR);
-       } else if (lp->shmem_length == SHMEM_64K) {
-               buf = (((short) page << 11) & 0xf800) + lp->shmem;
-               outb ((page >> 5), EWRK3_MPR);
-       } else {
-               printk (KERN_ERR "%s: Oops - your private data area is hosed!\n",
-                       dev->name);
-               BUG ();
-       }
-
-       /*
-        ** Set up the buffer control structures and copy the data from
-        ** the socket buffer to the shared memory .
-        */
-       if (lp->shmem_length == IO_ONLY) {
-               int i;
-               u_char *p = skb->data;
-               outb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
-               outb ((char) (skb->len & 0xff), EWRK3_DATA);
-               outb ((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
-               outb ((char) 0x04, EWRK3_DATA);
-               for (i = 0; i < skb->len; i++) {
-                       outb (*p++, EWRK3_DATA);
-               }
-               outb (page, EWRK3_TQ);  /* Start sending pkt */
-       } else {
-               writeb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), buf);   /* ctrl byte */
-               buf += 1;
-               writeb ((char) (skb->len & 0xff), buf); /* length (16 bit xfer) */
-               buf += 1;
-               if (lp->txc) {
-                       writeb(((skb->len >> 8) & 0xff) | XCT, buf);
-                       buf += 1;
-                       writeb (0x04, buf);     /* index byte */
-                       buf += 1;
-                       writeb (0x00, (buf + skb->len));        /* Write the XCT flag */
-                       memcpy_toio (buf, skb->data, PRELOAD);  /* Write PRELOAD bytes */
-                       outb (page, EWRK3_TQ);  /* Start sending pkt */
-                       memcpy_toio (buf + PRELOAD,
-                                        skb->data + PRELOAD,
-                                        skb->len - PRELOAD);
-                       writeb (0xff, (buf + skb->len));        /* Write the XCT flag */
-               } else {
-                       writeb ((skb->len >> 8) & 0xff, buf);
-                       buf += 1;
-                       writeb (0x04, buf);     /* index byte */
-                       buf += 1;
-                       memcpy_toio (buf, skb->data, skb->len); /* Write data bytes */
-                       outb (page, EWRK3_TQ);  /* Start sending pkt */
-               }
-       }
-
-       ENABLE_IRQs;
-       spin_unlock_irq (&lp->hw_lock);
-
-       dev->stats.tx_bytes += skb->len;
-       dev_kfree_skb (skb);
-
-       /* Check for free resources: stop Tx queue if there are none */
-       if (inb (EWRK3_FMQC) == 0)
-               netif_stop_queue (dev);
-
-       return NETDEV_TX_OK;
-
-err_out:
-       ENABLE_IRQs;
-       spin_unlock_irq (&lp->hw_lock);
-       return NETDEV_TX_BUSY;
-}
-
-/*
-   ** The EWRK3 interrupt handler.
- */
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct ewrk3_private *lp;
-       u_long iobase;
-       u_char icr, cr, csr;
-
-       lp = netdev_priv(dev);
-       iobase = dev->base_addr;
-
-       /* get the interrupt information */
-       csr = inb(EWRK3_CSR);
-
-       /*
-        ** Mask the EWRK3 board interrupts and turn on the LED
-        */
-       spin_lock(&lp->hw_lock);
-       DISABLE_IRQs;
-
-       cr = inb(EWRK3_CR);
-       cr |= lp->led_mask;
-       outb(cr, EWRK3_CR);
-
-       if (csr & CSR_RNE)      /* Rx interrupt (packet[s] arrived) */
-               ewrk3_rx(dev);
-
-       if (csr & CSR_TNE)      /* Tx interrupt (packet sent) */
-               ewrk3_tx(dev);
-
-       /*
-        ** Now deal with the TX/RX disable flags. These are set when there
-        ** are no more resources. If resources free up then enable these
-        ** interrupts, otherwise mask them - failure to do this will result
-        ** in the system hanging in an interrupt loop.
-        */
-       if (inb(EWRK3_FMQC)) {  /* any resources available? */
-               lp->irq_mask |= ICR_TXDM | ICR_RXDM;    /* enable the interrupt source */
-               csr &= ~(CSR_TXD | CSR_RXD);    /* ensure restart of a stalled TX or RX */
-               outb(csr, EWRK3_CSR);
-               netif_wake_queue(dev);
-       } else {
-               lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM);         /* disable the interrupt source */
-       }
-
-       /* Unmask the EWRK3 board interrupts and turn off the LED */
-       cr &= ~(lp->led_mask);
-       outb(cr, EWRK3_CR);
-       ENABLE_IRQs;
-       spin_unlock(&lp->hw_lock);
-       return IRQ_HANDLED;
-}
-
-/* Called with lp->hw_lock held */
-static int ewrk3_rx(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_long iobase = dev->base_addr;
-       int i, status = 0;
-       u_char page;
-       void __iomem *buf = NULL;
-
-       while (inb(EWRK3_RQC) && !status) {     /* Whilst there's incoming data */
-               if ((page = inb(EWRK3_RQ)) < lp->mPage) {       /* Get next entry's buffer page */
-                       /*
-                          ** Set up shared memory window and pointer into the window
-                        */
-                       if (lp->shmem_length == IO_ONLY) {
-                               outb(page, EWRK3_IOPR);
-                       } else if (lp->shmem_length == SHMEM_2K) {
-                               buf = lp->shmem;
-                               outb(page, EWRK3_MPR);
-                       } else if (lp->shmem_length == SHMEM_32K) {
-                               buf = (((short) page << 11) & 0x7800) + lp->shmem;
-                               outb((page >> 4), EWRK3_MPR);
-                       } else if (lp->shmem_length == SHMEM_64K) {
-                               buf = (((short) page << 11) & 0xf800) + lp->shmem;
-                               outb((page >> 5), EWRK3_MPR);
-                       } else {
-                               status = -1;
-                               printk("%s: Oops - your private data area is hosed!\n", dev->name);
-                       }
-
-                       if (!status) {
-                               char rx_status;
-                               int pkt_len;
-
-                               if (lp->shmem_length == IO_ONLY) {
-                                       rx_status = inb(EWRK3_DATA);
-                                       pkt_len = inb(EWRK3_DATA);
-                                       pkt_len |= ((u_short) inb(EWRK3_DATA) << 8);
-                               } else {
-                                       rx_status = readb(buf);
-                                       buf += 1;
-                                       pkt_len = readw(buf);
-                                       buf += 3;
-                               }
-
-                               if (!(rx_status & R_ROK)) {     /* There was an error. */
-                                       dev->stats.rx_errors++; /* Update the error stats. */
-                                       if (rx_status & R_DBE)
-                                               dev->stats.rx_frame_errors++;
-                                       if (rx_status & R_CRC)
-                                               dev->stats.rx_crc_errors++;
-                                       if (rx_status & R_PLL)
-                                               dev->stats.rx_fifo_errors++;
-                               } else {
-                                       struct sk_buff *skb;
-                                       skb = netdev_alloc_skb(dev,
-                                                       pkt_len + 2);
-
-                                       if (skb != NULL) {
-                                               unsigned char *p;
-                                               skb_reserve(skb, 2);    /* Align to 16 bytes */
-                                               p = skb_put(skb, pkt_len);
-
-                                               if (lp->shmem_length == IO_ONLY) {
-                                                       *p = inb(EWRK3_DATA);   /* dummy read */
-                                                       for (i = 0; i < pkt_len; i++) {
-                                                               *p++ = inb(EWRK3_DATA);
-                                                       }
-                                               } else {
-                                                       memcpy_fromio(p, buf, pkt_len);
-                                               }
-
-                                               for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) {
-                                                       if (pkt_len < i * EWRK3_PKT_BIN_SZ) {
-                                                               lp->pktStats.bins[i]++;
-                                                               i = EWRK3_PKT_STAT_SZ;
-                                                       }
-                                               }
-                                               p = skb->data;  /* Look at the dest addr */
-                                               if (is_multicast_ether_addr(p)) {
-                                                       if (is_broadcast_ether_addr(p)) {
-                                                               lp->pktStats.broadcast++;
-                                                       } else {
-                                                               lp->pktStats.multicast++;
-                                                       }
-                                               } else if (ether_addr_equal(p,
-                                                                           dev->dev_addr)) {
-                                                       lp->pktStats.unicast++;
-                                               }
-                                               lp->pktStats.bins[0]++;         /* Duplicates stats.rx_packets */
-                                               if (lp->pktStats.bins[0] == 0) {        /* Reset counters */
-                                                       memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-                                               }
-                                               /*
-                                                  ** Notify the upper protocol layers that there is another
-                                                  ** packet to handle
-                                                */
-                                               skb->protocol = eth_type_trans(skb, dev);
-                                               netif_rx(skb);
-
-                                               /*
-                                                  ** Update stats
-                                                */
-                                               dev->stats.rx_packets++;
-                                               dev->stats.rx_bytes += pkt_len;
-                                       } else {
-                                               printk("%s: Insufficient memory; nuking packet.\n", dev->name);
-                                               dev->stats.rx_dropped++;                /* Really, deferred. */
-                                               break;
-                                       }
-                               }
-                       }
-                       /*
-                          ** Return the received buffer to the free memory queue
-                        */
-                       outb(page, EWRK3_FMQ);
-               } else {
-                       printk("ewrk3_rx(): Illegal page number, page %d\n", page);
-                       printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
-               }
-       }
-       return status;
-}
-
-/*
-** Buffer sent - check for TX buffer errors.
-** Called with lp->hw_lock held
-*/
-static int ewrk3_tx(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_long iobase = dev->base_addr;
-       u_char tx_status;
-
-       while ((tx_status = inb(EWRK3_TDQ)) > 0) {      /* Whilst there's old buffers */
-               if (tx_status & T_VSTS) {       /* The status is valid */
-                       if (tx_status & T_TXE) {
-                               dev->stats.tx_errors++;
-                               if (tx_status & T_NCL)
-                                       dev->stats.tx_carrier_errors++;
-                               if (tx_status & T_LCL)
-                                       dev->stats.tx_window_errors++;
-                               if (tx_status & T_CTU) {
-                                       if ((tx_status & T_COLL) ^ T_XUR) {
-                                               lp->pktStats.tx_underruns++;
-                                       } else {
-                                               lp->pktStats.excessive_underruns++;
-                                       }
-                               } else if (tx_status & T_COLL) {
-                                       if ((tx_status & T_COLL) ^ T_XCOLL) {
-                                               dev->stats.collisions++;
-                                       } else {
-                                               lp->pktStats.excessive_collisions++;
-                                       }
-                               }
-                       } else {
-                               dev->stats.tx_packets++;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int ewrk3_close(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_long iobase = dev->base_addr;
-       u_char icr, csr;
-
-       netif_stop_queue(dev);
-
-       if (ewrk3_debug > 1) {
-               printk("%s: Shutting down ethercard, status was %2.2x.\n",
-                      dev->name, inb(EWRK3_CSR));
-       }
-       /*
-          ** We stop the EWRK3 here... mask interrupts and stop TX & RX
-        */
-       DISABLE_IRQs;
-
-       STOP_EWRK3;
-
-       /*
-          ** Clean out the TX and RX queues here (note that one entry
-          ** may get added to either the TXD or RX queues if the TX or RX
-          ** just starts processing a packet before the STOP_EWRK3 command
-          ** is received. This will be flushed in the ewrk3_open() call).
-        */
-       while (inb(EWRK3_TQ));
-       while (inb(EWRK3_TDQ));
-       while (inb(EWRK3_RQ));
-
-       if (!lp->hard_strapped) {
-               free_irq(dev->irq, dev);
-       }
-       return 0;
-}
-
-/*
-   ** Set or clear the multicast filter for this adapter.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       u_long iobase = dev->base_addr;
-       u_char csr;
-
-       csr = inb(EWRK3_CSR);
-
-       if (lp->shmem_length == IO_ONLY) {
-               lp->mctbl = NULL;
-       } else {
-               lp->mctbl = lp->shmem + PAGE0_HTE;
-       }
-
-       csr &= ~(CSR_PME | CSR_MCE);
-       if (dev->flags & IFF_PROMISC) {         /* set promiscuous mode */
-               csr |= CSR_PME;
-               outb(csr, EWRK3_CSR);
-       } else {
-               SetMulticastFilter(dev);
-               csr |= CSR_MCE;
-               outb(csr, EWRK3_CSR);
-       }
-}
-
-/*
-   ** Calculate the hash code and update the logical address filter
-   ** from a list of ethernet multicast addresses.
-   ** Little endian crc one liner from Matt Thomas, DEC.
-   **
-   ** Note that when clearing the table, the broadcast bit must remain asserted
-   ** to receive broadcast messages.
- */
-static void SetMulticastFilter(struct net_device *dev)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       struct netdev_hw_addr *ha;
-       u_long iobase = dev->base_addr;
-       int i;
-       char bit, byte;
-       short __iomem *p = lp->mctbl;
-       u16 hashcode;
-       u32 crc;
-
-       spin_lock_irq(&lp->hw_lock);
-
-       if (lp->shmem_length == IO_ONLY) {
-               outb(0, EWRK3_IOPR);
-               outw(PAGE0_HTE, EWRK3_PIR1);
-       } else {
-               outb(0, EWRK3_MPR);
-       }
-
-       if (dev->flags & IFF_ALLMULTI) {
-               for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-                       if (lp->shmem_length == IO_ONLY) {
-                               outb(0xff, EWRK3_DATA);
-                       } else {        /* memset didn't work here */
-                               writew(0xffff, p);
-                               p++;
-                               i++;
-                       }
-               }
-       } else {
-               /* Clear table except for broadcast bit */
-               if (lp->shmem_length == IO_ONLY) {
-                       for (i = 0; i < (HASH_TABLE_LEN >> 4) - 1; i++) {
-                               outb(0x00, EWRK3_DATA);
-                       }
-                       outb(0x80, EWRK3_DATA);
-                       i++;    /* insert the broadcast bit */
-                       for (; i < (HASH_TABLE_LEN >> 3); i++) {
-                               outb(0x00, EWRK3_DATA);
-                       }
-               } else {
-                       memset_io(lp->mctbl, 0, HASH_TABLE_LEN >> 3);
-                       writeb(0x80, lp->mctbl + (HASH_TABLE_LEN >> 4) - 1);
-               }
-
-               /* Update table */
-               netdev_for_each_mc_addr(ha, dev) {
-                       crc = ether_crc_le(ETH_ALEN, ha->addr);
-                       hashcode = crc & ((1 << 9) - 1);        /* hashcode is 9 LSb of CRC */
-
-                       byte = hashcode >> 3;   /* bit[3-8] -> byte in filter */
-                       bit = 1 << (hashcode & 0x07);   /* bit[0-2] -> bit in byte */
-
-                       if (lp->shmem_length == IO_ONLY) {
-                               u_char tmp;
-
-                               outw(PAGE0_HTE + byte, EWRK3_PIR1);
-                               tmp = inb(EWRK3_DATA);
-                               tmp |= bit;
-                               outw(PAGE0_HTE + byte, EWRK3_PIR1);
-                               outb(tmp, EWRK3_DATA);
-                       } else {
-                               writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte);
-                       }
-               }
-       }
-
-       spin_unlock_irq(&lp->hw_lock);
-}
-
-/*
-   ** ISA bus I/O device probe
- */
-static int __init isa_probe(struct net_device *dev, u_long ioaddr)
-{
-       int i = num_ewrks3s, maxSlots;
-       int ret = -ENODEV;
-
-       u_long iobase;
-
-       if (ioaddr >= 0x400)
-               goto out;
-
-       if (ioaddr == 0) {      /* Autoprobing */
-               iobase = EWRK3_IO_BASE;         /* Get the first slot address */
-               maxSlots = 24;
-       } else {                /* Probe a specific location */
-               iobase = ioaddr;
-               maxSlots = i + 1;
-       }
-
-       for (; (i < maxSlots) && (dev != NULL);
-            iobase += EWRK3_IOP_INC, i++)
-       {
-               if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME)) {
-                       if (DevicePresent(iobase) == 0) {
-                               int irq = dev->irq;
-                               ret = ewrk3_hw_init(dev, iobase);
-                               if (!ret)
-                                       break;
-                               dev->irq = irq;
-                       }
-                       release_region(iobase, EWRK3_TOTAL_SIZE);
-               }
-       }
- out:
-
-       return ret;
-}
-
-/*
-   ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-   ** the motherboard.
- */
-static int __init eisa_probe(struct net_device *dev, u_long ioaddr)
-{
-       int i, maxSlots;
-       u_long iobase;
-       int ret = -ENODEV;
-
-       if (ioaddr < 0x1000)
-               goto out;
-
-       iobase = ioaddr;
-       i = (ioaddr >> 12);
-       maxSlots = i + 1;
-
-       for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
-               if (EISA_signature(name, EISA_ID) == 0) {
-                       if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME) &&
-                           DevicePresent(iobase) == 0) {
-                               int irq = dev->irq;
-                               ret = ewrk3_hw_init(dev, iobase);
-                               if (!ret)
-                                       break;
-                               dev->irq = irq;
-                       }
-                       release_region(iobase, EWRK3_TOTAL_SIZE);
-               }
-       }
-
- out:
-       return ret;
-}
-
-
-/*
-   ** Read the EWRK3 EEPROM using this routine
- */
-static int Read_EEPROM(u_long iobase, u_char eaddr)
-{
-       int i;
-
-       outb((eaddr & 0x3f), EWRK3_PIR1);       /* set up 6 bits of address info */
-       outb(EEPROM_RD, EWRK3_IOPR);    /* issue read command */
-       for (i = 0; i < 5000; i++)
-               inb(EWRK3_CSR); /* wait 1msec */
-
-       return inw(EWRK3_EPROM1);       /* 16 bits data return */
-}
-
-/*
-   ** Write the EWRK3 EEPROM using this routine
- */
-static int Write_EEPROM(short data, u_long iobase, u_char eaddr)
-{
-       int i;
-
-       outb(EEPROM_WR_EN, EWRK3_IOPR);         /* issue write enable command */
-       for (i = 0; i < 5000; i++)
-               inb(EWRK3_CSR); /* wait 1msec */
-       outw(data, EWRK3_EPROM1);       /* write data to register */
-       outb((eaddr & 0x3f), EWRK3_PIR1);       /* set up 6 bits of address info */
-       outb(EEPROM_WR, EWRK3_IOPR);    /* issue write command */
-       for (i = 0; i < 75000; i++)
-               inb(EWRK3_CSR); /* wait 15msec */
-       outb(EEPROM_WR_DIS, EWRK3_IOPR);        /* issue write disable command */
-       for (i = 0; i < 5000; i++)
-               inb(EWRK3_CSR); /* wait 1msec */
-
-       return 0;
-}
-
-/*
-   ** Look for a particular board name in the on-board EEPROM.
- */
-static void __init EthwrkSignature(char *name, char *eeprom_image)
-{
-       int i;
-       char *signatures[] = EWRK3_SIGNATURE;
-
-       for (i=0; *signatures[i] != '\0'; i++)
-               if( !strncmp(eeprom_image+EEPROM_PNAME7, signatures[i], strlen(signatures[i])) )
-                       break;
-
-       if (*signatures[i] != '\0') {
-               memcpy(name, eeprom_image+EEPROM_PNAME7, EWRK3_STRLEN);
-               name[EWRK3_STRLEN] = '\0';
-       } else
-               name[0] = '\0';
-}
-
-/*
-   ** Look for a special sequence in the Ethernet station address PROM that
-   ** is common across all EWRK3 products.
-   **
-   ** Search the Ethernet address ROM for the signature. Since the ROM address
-   ** counter can start at an arbitrary point, the search must include the entire
-   ** probe sequence length plus the (length_of_the_signature - 1).
-   ** Stop the search IMMEDIATELY after the signature is found so that the
-   ** PROM address counter is correctly positioned at the start of the
-   ** ethernet address for later read out.
- */
-
-static int __init DevicePresent(u_long iobase)
-{
-       union {
-               struct {
-                       u32 a;
-                       u32 b;
-               } llsig;
-               char Sig[sizeof(u32) << 1];
-       }
-       dev;
-       short sigLength;
-       char data;
-       int i, j, status = 0;
-
-       dev.llsig.a = ETH_PROM_SIG;
-       dev.llsig.b = ETH_PROM_SIG;
-       sigLength = sizeof(u32) << 1;
-
-       for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
-               data = inb(EWRK3_APROM);
-               if (dev.Sig[j] == data) {       /* track signature */
-                       j++;
-               } else {        /* lost signature; begin search again */
-                       if (data == dev.Sig[0]) {
-                               j = 1;
-                       } else {
-                               j = 0;
-                       }
-               }
-       }
-
-       if (j != sigLength) {
-               status = -ENODEV;       /* search failed */
-       }
-       return status;
-}
-
-static u_char __init get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType)
-{
-       int i, j, k;
-       u_short chksum;
-       u_char crc, lfsr, sd, status = 0;
-       u_long iobase = dev->base_addr;
-       u16 tmp;
-
-       if (chipType == LeMAC2) {
-               for (crc = 0x6a, j = 0; j < ETH_ALEN; j++) {
-                       sd = dev->dev_addr[j] = eeprom_image[EEPROM_PADDR0 + j];
-                       outb(dev->dev_addr[j], EWRK3_PAR0 + j);
-                       for (k = 0; k < 8; k++, sd >>= 1) {
-                               lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7;
-                               crc = (crc >> 1) + lfsr;
-                       }
-               }
-               if (crc != eeprom_image[EEPROM_PA_CRC])
-                       status = -1;
-       } else {
-               for (i = 0, k = 0; i < ETH_ALEN;) {
-                       k <<= 1;
-                       if (k > 0xffff)
-                               k -= 0xffff;
-
-                       k += (u_char) (tmp = inb(EWRK3_APROM));
-                       dev->dev_addr[i] = (u_char) tmp;
-                       outb(dev->dev_addr[i], EWRK3_PAR0 + i);
-                       i++;
-                       k += (u_short) ((tmp = inb(EWRK3_APROM)) << 8);
-                       dev->dev_addr[i] = (u_char) tmp;
-                       outb(dev->dev_addr[i], EWRK3_PAR0 + i);
-                       i++;
-
-                       if (k > 0xffff)
-                               k -= 0xffff;
-               }
-               if (k == 0xffff)
-                       k = 0;
-               chksum = inb(EWRK3_APROM);
-               chksum |= (inb(EWRK3_APROM) << 8);
-               if (k != chksum)
-                       status = -1;
-       }
-
-       return status;
-}
-
-/*
-   ** Look for a particular board name in the EISA configuration space
- */
-static int __init EISA_signature(char *name, s32 eisa_id)
-{
-       u_long i;
-       char *signatures[] = EWRK3_SIGNATURE;
-       char ManCode[EWRK3_STRLEN];
-       union {
-               s32 ID;
-               char Id[4];
-       } Eisa;
-       int status = 0;
-
-       *name = '\0';
-       for (i = 0; i < 4; i++) {
-               Eisa.Id[i] = inb(eisa_id + i);
-       }
-
-       ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40);
-       ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40);
-       ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30);
-       ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30);
-       ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30);
-       ManCode[5] = '\0';
-
-       for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) {
-               if (strstr(ManCode, signatures[i]) != NULL) {
-                       strcpy(name, ManCode);
-                       status = 1;
-               }
-       }
-
-       return status;          /* return the device name string */
-}
-
-static void ewrk3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
-
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->fw_version, "%d", fwrev);
-       strcpy(info->bus_info, "N/A");
-       info->eedump_len = EEPROM_MAX;
-}
-
-static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       unsigned long iobase = dev->base_addr;
-       u8 cr = inb(EWRK3_CR);
-
-       switch (lp->adapter_name[4]) {
-       case '3': /* DE203 */
-               ecmd->supported = SUPPORTED_BNC;
-               ecmd->port = PORT_BNC;
-               break;
-
-       case '4': /* DE204 */
-               ecmd->supported = SUPPORTED_TP;
-               ecmd->port = PORT_TP;
-               break;
-
-       case '5': /* DE205 */
-               ecmd->supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
-               ecmd->autoneg = !(cr & CR_APD);
-               /*
-               ** Port is only valid if autoneg is disabled
-               ** and even then we don't know if AUI is jumpered.
-               */
-               if (!ecmd->autoneg)
-                       ecmd->port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
-               break;
-       }
-
-       ecmd->supported |= SUPPORTED_10baseT_Half;
-       ethtool_cmd_speed_set(ecmd, SPEED_10);
-       ecmd->duplex = DUPLEX_HALF;
-       return 0;
-}
-
-static int ewrk3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       unsigned long iobase = dev->base_addr;
-       unsigned long flags;
-       u8 cr;
-
-       /* DE205 is the only card with anything to set */
-       if (lp->adapter_name[4] != '5')
-               return -EOPNOTSUPP;
-
-       /* Sanity-check parameters */
-       if (ecmd->speed != SPEED_10)
-               return -EINVAL;
-       if (ecmd->port != PORT_TP && ecmd->port != PORT_BNC)
-               return -EINVAL; /* AUI is not software-selectable */
-       if (ecmd->transceiver != XCVR_INTERNAL)
-               return -EINVAL;
-       if (ecmd->duplex != DUPLEX_HALF)
-               return -EINVAL;
-       if (ecmd->phy_address != 0)
-               return -EINVAL;
-
-       spin_lock_irqsave(&lp->hw_lock, flags);
-       cr = inb(EWRK3_CR);
-
-       /* If Autoneg is set, change to Auto Port mode */
-       /* Otherwise, disable Auto Port and set port explicitly */
-       if (ecmd->autoneg) {
-               cr &= ~CR_APD;
-       } else {
-               cr |= CR_APD;
-               if (ecmd->port == PORT_TP)
-                       cr &= ~CR_PSEL;         /* Force TP */
-               else
-                       cr |= CR_PSEL;          /* Force BNC */
-       }
-
-       /* Commit the changes */
-       outb(cr, EWRK3_CR);
-       spin_unlock_irqrestore(&lp->hw_lock, flags);
-       return 0;
-}
-
-static u32 ewrk3_get_link(struct net_device *dev)
-{
-       unsigned long iobase = dev->base_addr;
-       u8 cmr = inb(EWRK3_CMR);
-       /* DE203 has BNC only and link status does not apply */
-       /* On DE204 this is always valid since TP is the only port. */
-       /* On DE205 this reflects TP status even if BNC or AUI is selected. */
-       return !(cmr & CMR_LINK);
-}
-
-static int ewrk3_set_phys_id(struct net_device *dev,
-                            enum ethtool_phys_id_state state)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       unsigned long iobase = dev->base_addr;
-       u8 cr;
-
-       spin_lock_irq(&lp->hw_lock);
-
-       switch (state) {
-       case ETHTOOL_ID_ACTIVE:
-               /* Prevent ISR from twiddling the LED */
-               lp->led_mask = 0;
-               spin_unlock_irq(&lp->hw_lock);
-               return 2;       /* cycle on/off twice per second */
-
-       case ETHTOOL_ID_ON:
-               cr = inb(EWRK3_CR);
-               outb(cr | CR_LED, EWRK3_CR);
-               break;
-
-       case ETHTOOL_ID_OFF:
-               cr = inb(EWRK3_CR);
-               outb(cr & ~CR_LED, EWRK3_CR);
-               break;
-
-       case ETHTOOL_ID_INACTIVE:
-               lp->led_mask = CR_LED;
-               cr = inb(EWRK3_CR);
-               outb(cr & ~CR_LED, EWRK3_CR);
-       }
-       spin_unlock_irq(&lp->hw_lock);
-
-       return 0;
-}
-
-static const struct ethtool_ops ethtool_ops_203 = {
-       .get_drvinfo = ewrk3_get_drvinfo,
-       .get_settings = ewrk3_get_settings,
-       .set_settings = ewrk3_set_settings,
-       .set_phys_id = ewrk3_set_phys_id,
-};
-
-static const struct ethtool_ops ethtool_ops = {
-       .get_drvinfo = ewrk3_get_drvinfo,
-       .get_settings = ewrk3_get_settings,
-       .set_settings = ewrk3_set_settings,
-       .get_link = ewrk3_get_link,
-       .set_phys_id = ewrk3_set_phys_id,
-};
-
-/*
-   ** Perform IOCTL call functions here. Some are privileged operations and the
-   ** effective uid is checked in those cases.
- */
-static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct ewrk3_private *lp = netdev_priv(dev);
-       struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_ifru;
-       u_long iobase = dev->base_addr;
-       int i, j, status = 0;
-       u_char csr;
-       unsigned long flags;
-       union ewrk3_addr {
-               u_char addr[HASH_TABLE_LEN * ETH_ALEN];
-               u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-       };
-
-       union ewrk3_addr *tmp;
-
-       /* All we handle are private IOCTLs */
-       if (cmd != EWRK3IOCTL)
-               return -EOPNOTSUPP;
-
-       tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
-       if(tmp==NULL)
-               return -ENOMEM;
-
-       switch (ioc->cmd) {
-       case EWRK3_GET_HWADDR:  /* Get the hardware address */
-               for (i = 0; i < ETH_ALEN; i++) {
-                       tmp->addr[i] = dev->dev_addr[i];
-               }
-               ioc->len = ETH_ALEN;
-               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-                       status = -EFAULT;
-               break;
-
-       case EWRK3_SET_HWADDR:  /* Set the hardware address */
-               if (capable(CAP_NET_ADMIN)) {
-                       spin_lock_irqsave(&lp->hw_lock, flags);
-                       csr = inb(EWRK3_CSR);
-                       csr |= (CSR_TXD | CSR_RXD);
-                       outb(csr, EWRK3_CSR);   /* Disable the TX and RX */
-                       spin_unlock_irqrestore(&lp->hw_lock, flags);
-
-                       if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
-                               status = -EFAULT;
-                               break;
-                       }
-                       spin_lock_irqsave(&lp->hw_lock, flags);
-                       for (i = 0; i < ETH_ALEN; i++) {
-                               dev->dev_addr[i] = tmp->addr[i];
-                               outb(tmp->addr[i], EWRK3_PAR0 + i);
-                       }
-
-                       csr = inb(EWRK3_CSR);
-                       csr &= ~(CSR_TXD | CSR_RXD);    /* Enable the TX and RX */
-                       outb(csr, EWRK3_CSR);
-                       spin_unlock_irqrestore(&lp->hw_lock, flags);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_SET_PROM:    /* Set Promiscuous Mode */
-               if (capable(CAP_NET_ADMIN)) {
-                       spin_lock_irqsave(&lp->hw_lock, flags);
-                       csr = inb(EWRK3_CSR);
-                       csr |= CSR_PME;
-                       csr &= ~CSR_MCE;
-                       outb(csr, EWRK3_CSR);
-                       spin_unlock_irqrestore(&lp->hw_lock, flags);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_CLR_PROM:    /* Clear Promiscuous Mode */
-               if (capable(CAP_NET_ADMIN)) {
-                       spin_lock_irqsave(&lp->hw_lock, flags);
-                       csr = inb(EWRK3_CSR);
-                       csr &= ~CSR_PME;
-                       outb(csr, EWRK3_CSR);
-                       spin_unlock_irqrestore(&lp->hw_lock, flags);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_GET_MCA:     /* Get the multicast address table */
-               spin_lock_irqsave(&lp->hw_lock, flags);
-               if (lp->shmem_length == IO_ONLY) {
-                       outb(0, EWRK3_IOPR);
-                       outw(PAGE0_HTE, EWRK3_PIR1);
-                       for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-                               tmp->addr[i] = inb(EWRK3_DATA);
-                       }
-               } else {
-                       outb(0, EWRK3_MPR);
-                       memcpy_fromio(tmp->addr, lp->shmem + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
-               }
-               spin_unlock_irqrestore(&lp->hw_lock, flags);
-
-               ioc->len = (HASH_TABLE_LEN >> 3);
-               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-                       status = -EFAULT;
-
-               break;
-       case EWRK3_SET_MCA:     /* Set a multicast address */
-               if (capable(CAP_NET_ADMIN)) {
-                       if (ioc->len > HASH_TABLE_LEN) {
-                               status = -EINVAL;
-                               break;
-                       }
-                       if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
-                               status = -EFAULT;
-                               break;
-                       }
-                       set_multicast_list(dev);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_CLR_MCA:     /* Clear all multicast addresses */
-               if (capable(CAP_NET_ADMIN)) {
-                       set_multicast_list(dev);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_MCA_EN:      /* Enable multicast addressing */
-               if (capable(CAP_NET_ADMIN)) {
-                       spin_lock_irqsave(&lp->hw_lock, flags);
-                       csr = inb(EWRK3_CSR);
-                       csr |= CSR_MCE;
-                       csr &= ~CSR_PME;
-                       outb(csr, EWRK3_CSR);
-                       spin_unlock_irqrestore(&lp->hw_lock, flags);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_GET_STATS: { /* Get the driver statistics */
-               struct ewrk3_stats *tmp_stats =
-                       kmalloc(sizeof(lp->pktStats), GFP_KERNEL);
-               if (!tmp_stats) {
-                       status = -ENOMEM;
-                       break;
-               }
-
-               spin_lock_irqsave(&lp->hw_lock, flags);
-               memcpy(tmp_stats, &lp->pktStats, sizeof(lp->pktStats));
-               spin_unlock_irqrestore(&lp->hw_lock, flags);
-
-               ioc->len = sizeof(lp->pktStats);
-               if (copy_to_user(ioc->data, tmp_stats, sizeof(lp->pktStats)))
-                       status = -EFAULT;
-               kfree(tmp_stats);
-               break;
-       }
-       case EWRK3_CLR_STATS:   /* Zero out the driver statistics */
-               if (capable(CAP_NET_ADMIN)) {
-                       spin_lock_irqsave(&lp->hw_lock, flags);
-                       memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-                       spin_unlock_irqrestore(&lp->hw_lock,flags);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_GET_CSR:     /* Get the CSR Register contents */
-               tmp->addr[0] = inb(EWRK3_CSR);
-               ioc->len = 1;
-               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-                       status = -EFAULT;
-               break;
-       case EWRK3_SET_CSR:     /* Set the CSR Register contents */
-               if (capable(CAP_NET_ADMIN)) {
-                       if (copy_from_user(tmp->addr, ioc->data, 1)) {
-                               status = -EFAULT;
-                               break;
-                       }
-                       outb(tmp->addr[0], EWRK3_CSR);
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_GET_EEPROM:  /* Get the EEPROM contents */
-               if (capable(CAP_NET_ADMIN)) {
-                       for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-                               tmp->val[i] = (short) Read_EEPROM(iobase, i);
-                       }
-                       i = EEPROM_MAX;
-                       tmp->addr[i++] = inb(EWRK3_CMR);                /* Config/Management Reg. */
-                       for (j = 0; j < ETH_ALEN; j++) {
-                               tmp->addr[i++] = inb(EWRK3_PAR0 + j);
-                       }
-                       ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
-                       if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-                               status = -EFAULT;
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_SET_EEPROM:  /* Set the EEPROM contents */
-               if (capable(CAP_NET_ADMIN)) {
-                       if (copy_from_user(tmp->addr, ioc->data, EEPROM_MAX)) {
-                               status = -EFAULT;
-                               break;
-                       }
-                       for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-                               Write_EEPROM(tmp->val[i], iobase, i);
-                       }
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_GET_CMR:     /* Get the CMR Register contents */
-               tmp->addr[0] = inb(EWRK3_CMR);
-               ioc->len = 1;
-               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-                       status = -EFAULT;
-               break;
-       case EWRK3_SET_TX_CUT_THRU:     /* Set TX cut through mode */
-               if (capable(CAP_NET_ADMIN)) {
-                       lp->txc = 1;
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       case EWRK3_CLR_TX_CUT_THRU:     /* Clear TX cut through mode */
-               if (capable(CAP_NET_ADMIN)) {
-                       lp->txc = 0;
-               } else {
-                       status = -EPERM;
-               }
-
-               break;
-       default:
-               status = -EOPNOTSUPP;
-       }
-       kfree(tmp);
-       return status;
-}
-
-#ifdef MODULE
-static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];
-static int ndevs;
-static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, byte, NULL, 0);
-MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)");
-
-static __exit void ewrk3_exit_module(void)
-{
-       int i;
-
-       for( i=0; i<ndevs; i++ ) {
-               struct net_device *dev = ewrk3_devs[i];
-               struct ewrk3_private *lp = netdev_priv(dev);
-               ewrk3_devs[i] = NULL;
-               unregister_netdev(dev);
-               release_region(dev->base_addr, EWRK3_TOTAL_SIZE);
-               iounmap(lp->shmem);
-               free_netdev(dev);
-       }
-}
-
-static __init int ewrk3_init_module(void)
-{
-       int i=0;
-
-       while( io[i] && irq[i] ) {
-               struct net_device *dev
-                       = alloc_etherdev(sizeof(struct ewrk3_private));
-
-               if (!dev)
-                       break;
-
-               if (ewrk3_probe1(dev, io[i], irq[i]) != 0) {
-                       free_netdev(dev);
-                       break;
-               }
-
-               ewrk3_devs[ndevs++] = dev;
-               i++;
-       }
-
-       return ndevs ? 0 : -EIO;
-}
-
-
-/* Hack for breakage in new module stuff */
-module_exit(ewrk3_exit_module);
-module_init(ewrk3_init_module);
-#endif                         /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dec/ewrk3.h b/drivers/net/ethernet/dec/ewrk3.h
deleted file mode 100644 (file)
index 8e0ee90..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
-    Written 1994 by David C. Davies.
-
-    Copyright 1994 Digital Equipment Corporation.
-
-    This software may be used and distributed according to  the terms of the
-    GNU General Public License, incorporated herein by reference.
-
-    The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
-    Equipment Corporation, 550 King Street, Littleton MA 01460.
-
-    =========================================================================
-*/
-
-/*
-** I/O Address Register Map
-*/
-#define EWRK3_CSR    iobase+0x00   /* Control and Status Register */
-#define EWRK3_CR     iobase+0x01   /* Control Register */
-#define EWRK3_ICR    iobase+0x02   /* Interrupt Control Register */
-#define EWRK3_TSR    iobase+0x03   /* Transmit Status Register */
-#define EWRK3_RSVD1  iobase+0x04   /* RESERVED */
-#define EWRK3_RSVD2  iobase+0x05   /* RESERVED */
-#define EWRK3_FMQ    iobase+0x06   /* Free Memory Queue */
-#define EWRK3_FMQC   iobase+0x07   /* Free Memory Queue Counter */
-#define EWRK3_RQ     iobase+0x08   /* Receive Queue */
-#define EWRK3_RQC    iobase+0x09   /* Receive Queue Counter */
-#define EWRK3_TQ     iobase+0x0a   /* Transmit Queue */
-#define EWRK3_TQC    iobase+0x0b   /* Transmit Queue Counter */
-#define EWRK3_TDQ    iobase+0x0c   /* Transmit Done Queue */
-#define EWRK3_TDQC   iobase+0x0d   /* Transmit Done Queue Counter */
-#define EWRK3_PIR1   iobase+0x0e   /* Page Index Register 1 */
-#define EWRK3_PIR2   iobase+0x0f   /* Page Index Register 2 */
-#define EWRK3_DATA   iobase+0x10   /* Data Register */
-#define EWRK3_IOPR   iobase+0x11   /* I/O Page Register */
-#define EWRK3_IOBR   iobase+0x12   /* I/O Base Register */
-#define EWRK3_MPR    iobase+0x13   /* Memory Page Register */
-#define EWRK3_MBR    iobase+0x14   /* Memory Base Register */
-#define EWRK3_APROM  iobase+0x15   /* Address PROM */
-#define EWRK3_EPROM1 iobase+0x16   /* EEPROM Data Register 1 */
-#define EWRK3_EPROM2 iobase+0x17   /* EEPROM Data Register 2 */
-#define EWRK3_PAR0   iobase+0x18   /* Physical Address Register 0 */
-#define EWRK3_PAR1   iobase+0x19   /* Physical Address Register 1 */
-#define EWRK3_PAR2   iobase+0x1a   /* Physical Address Register 2 */
-#define EWRK3_PAR3   iobase+0x1b   /* Physical Address Register 3 */
-#define EWRK3_PAR4   iobase+0x1c   /* Physical Address Register 4 */
-#define EWRK3_PAR5   iobase+0x1d   /* Physical Address Register 5 */
-#define EWRK3_CMR    iobase+0x1e   /* Configuration/Management Register */
-
-/*
-** Control Page Map
-*/
-#define PAGE0_FMQ     0x000         /* Free Memory Queue */
-#define PAGE0_RQ      0x080         /* Receive Queue */
-#define PAGE0_TQ      0x100         /* Transmit Queue */
-#define PAGE0_TDQ     0x180         /* Transmit Done Queue */
-#define PAGE0_HTE     0x200         /* Hash Table Entries */
-#define PAGE0_RSVD    0x240         /* RESERVED */
-#define PAGE0_USRD    0x600         /* User Data */
-
-/*
-** Control and Status Register bit definitions (EWRK3_CSR)
-*/
-#define CSR_RA         0x80        /* Runt Accept */
-#define CSR_PME                0x40        /* Promiscuous Mode Enable */
-#define CSR_MCE                0x20        /* Multicast Enable */
-#define CSR_TNE                0x08        /* TX Done Queue Not Empty */
-#define CSR_RNE                0x04        /* RX Queue Not Empty */
-#define CSR_TXD                0x02        /* TX Disable */
-#define CSR_RXD                0x01        /* RX Disable */
-
-/*
-** Control Register bit definitions (EWRK3_CR)
-*/
-#define CR_APD         0x80    /* Auto Port Disable */
-#define CR_PSEL                0x40    /* Port Select (0->TP port) */
-#define CR_LBCK                0x20    /* LoopBaCK enable */
-#define CR_FDUP                0x10    /* Full DUPlex enable */
-#define CR_FBUS                0x08    /* Fast BUS enable (ISA clk > 8.33MHz) */
-#define CR_EN_16       0x04    /* ENable 16 bit memory accesses */
-#define CR_LED         0x02    /* LED (1-> turn on) */
-
-/*
-** Interrupt Control Register bit definitions (EWRK3_ICR)
-*/
-#define ICR_IE         0x80    /* Interrupt Enable */
-#define ICR_IS         0x60    /* Interrupt Selected */
-#define ICR_TNEM       0x08    /* TNE Mask (0->mask) */
-#define ICR_RNEM       0x04    /* RNE Mask (0->mask) */
-#define ICR_TXDM       0x02    /* TXD Mask (0->mask) */
-#define ICR_RXDM       0x01    /* RXD Mask (0->mask) */
-
-/*
-** Transmit Status Register bit definitions (EWRK3_TSR)
-*/
-#define TSR_NCL                0x80    /* No Carrier Loopback */
-#define TSR_ID         0x40    /* Initially Deferred */
-#define TSR_LCL                0x20    /* Late CoLlision */
-#define TSR_ECL                0x10    /* Excessive CoLlisions */
-#define TSR_RCNTR      0x0f    /* Retries CouNTeR */
-
-/*
-** I/O Page Register bit definitions (EWRK3_IOPR)
-*/
-#define EEPROM_INIT    0xc0    /* EEPROM INIT command */
-#define EEPROM_WR_EN   0xc8    /* EEPROM WRITE ENABLE command */
-#define EEPROM_WR      0xd0    /* EEPROM WRITE command */
-#define EEPROM_WR_DIS  0xd8    /* EEPROM WRITE DISABLE command */
-#define EEPROM_RD      0xe0    /* EEPROM READ command */
-
-/*
-** I/O Base Register bit definitions (EWRK3_IOBR)
-*/
-#define EISA_REGS_EN   0x20    /* Enable EISA ID and Control Registers */
-#define EISA_IOB        0x1f   /* Compare bits for I/O Base Address */
-
-/*
-** I/O Configuration/Management Register bit definitions (EWRK3_CMR)
-*/
-#define CMR_RA          0x80    /* Read Ahead */
-#define CMR_WB          0x40    /* Write Behind */
-#define CMR_LINK        0x20   /* 0->TP */
-#define CMR_POLARITY    0x10   /* Informational */
-#define CMR_NO_EEPROM  0x0c    /* NO_EEPROM<1:0> pin status */
-#define CMR_HS          0x08   /* Hard Strapped pin status (LeMAC2) */
-#define CMR_PNP         0x04    /* Plug 'n Play */
-#define CMR_DRAM        0x02   /* 0-> 1DRAM, 1-> 2 DRAM on board */
-#define CMR_0WS         0x01    /* Zero Wait State */
-
-/*
-** MAC Receive Status Register bit definitions
-*/
-
-#define R_ROK          0x80    /* Receive OK summary */
-#define R_IAM          0x10    /* Individual Address Match */
-#define R_MCM          0x08    /* MultiCast Match */
-#define R_DBE          0x04    /* Dribble Bit Error */
-#define R_CRC          0x02    /* CRC error */
-#define R_PLL          0x01    /* Phase Lock Lost */
-
-/*
-** MAC Transmit Control Register bit definitions
-*/
-
-#define TCR_SQEE       0x40    /* SQE Enable - look for heartbeat  */
-#define TCR_SED        0x20    /* Stop when Error Detected */
-#define TCR_QMODE      0x10    /* Q_MODE */
-#define TCR_LAB         0x08   /* Less Aggressive Backoff */
-#define TCR_PAD        0x04    /* PAD Runt Packets */
-#define TCR_IFC        0x02    /* Insert Frame Check */
-#define TCR_ISA        0x01    /* Insert Source Address */
-
-/*
-** MAC Transmit Status Register bit definitions
-*/
-
-#define T_VSTS         0x80    /* Valid STatuS */
-#define T_CTU          0x40    /* Cut Through Used */
-#define T_SQE          0x20    /* Signal Quality Error */
-#define T_NCL          0x10    /* No Carrier Loopback */
-#define T_LCL           0x08   /* Late Collision */
-#define T_ID           0x04    /* Initially Deferred */
-#define T_COLL         0x03    /* COLLision status */
-#define T_XCOLL         0x03    /* Excessive Collisions */
-#define T_MCOLL         0x02    /* Multiple Collisions */
-#define T_OCOLL         0x01    /* One Collision */
-#define T_NOCOLL        0x00    /* No Collisions */
-#define T_XUR           0x03    /* Excessive Underruns */
-#define T_TXE           0x7f    /* TX Errors */
-
-/*
-** EISA Configuration Register bit definitions
-*/
-
-#define EISA_ID       iobase + 0x0c80  /* EISA ID Registers */
-#define EISA_ID0      iobase + 0x0c80  /* EISA ID Register 0 */
-#define EISA_ID1      iobase + 0x0c81  /* EISA ID Register 1 */
-#define EISA_ID2      iobase + 0x0c82  /* EISA ID Register 2 */
-#define EISA_ID3      iobase + 0x0c83  /* EISA ID Register 3 */
-#define EISA_CR       iobase + 0x0c84  /* EISA Control Register */
-
-/*
-** EEPROM BYTES
-*/
-#define EEPROM_MEMB     0x00
-#define EEPROM_IOB      0x01
-#define EEPROM_EISA_ID0 0x02
-#define EEPROM_EISA_ID1 0x03
-#define EEPROM_EISA_ID2 0x04
-#define EEPROM_EISA_ID3 0x05
-#define EEPROM_MISC0    0x06
-#define EEPROM_MISC1    0x07
-#define EEPROM_PNAME7   0x08
-#define EEPROM_PNAME6   0x09
-#define EEPROM_PNAME5   0x0a
-#define EEPROM_PNAME4   0x0b
-#define EEPROM_PNAME3   0x0c
-#define EEPROM_PNAME2   0x0d
-#define EEPROM_PNAME1   0x0e
-#define EEPROM_PNAME0   0x0f
-#define EEPROM_SWFLAGS  0x10
-#define EEPROM_HWCAT    0x11
-#define EEPROM_NETMAN2  0x12
-#define EEPROM_REVLVL   0x13
-#define EEPROM_NETMAN0  0x14
-#define EEPROM_NETMAN1  0x15
-#define EEPROM_CHIPVER  0x16
-#define EEPROM_SETUP    0x17
-#define EEPROM_PADDR0   0x18
-#define EEPROM_PADDR1   0x19
-#define EEPROM_PADDR2   0x1a
-#define EEPROM_PADDR3   0x1b
-#define EEPROM_PADDR4   0x1c
-#define EEPROM_PADDR5   0x1d
-#define EEPROM_PA_CRC   0x1e
-#define EEPROM_CHKSUM   0x1f
-
-/*
-** EEPROM bytes for checksumming
-*/
-#define EEPROM_MAX      32             /* bytes */
-
-/*
-** EEPROM MISCELLANEOUS FLAGS
-*/
-#define RBE_SHADOW     0x0100  /* Remote Boot Enable Shadow */
-#define READ_AHEAD      0x0080  /* Read Ahead feature */
-#define IRQ_SEL2        0x0070  /* IRQ line selection (LeMAC2) */
-#define IRQ_SEL         0x0060  /* IRQ line selection */
-#define FAST_BUS        0x0008  /* ISA Bus speeds > 8.33MHz */
-#define ENA_16          0x0004  /* Enables 16 bit memory transfers */
-#define WRITE_BEHIND    0x0002  /* Write Behind feature */
-#define _0WS_ENA        0x0001  /* Zero Wait State Enable */
-
-/*
-** EEPROM NETWORK MANAGEMENT FLAGS
-*/
-#define NETMAN_POL      0x04    /* Polarity defeat */
-#define NETMAN_LINK     0x02    /* Link defeat */
-#define NETMAN_CCE      0x01    /* Custom Counters Enable */
-
-/*
-** EEPROM SW FLAGS
-*/
-#define SW_SQE         0x10    /* Signal Quality Error */
-#define SW_LAB         0x08    /* Less Aggressive Backoff */
-#define SW_INIT                0x04    /* Initialized */
-#define SW_TIMEOUT             0x02    /* 0:2.5 mins, 1: 30 secs */
-#define SW_REMOTE              0x01    /* Remote Boot Enable -> 1 */
-
-/*
-** EEPROM SETUP FLAGS
-*/
-#define SETUP_APD      0x80    /* AutoPort Disable */
-#define SETUP_PS       0x40    /* Port Select */
-#define SETUP_MP       0x20    /* MultiPort */
-#define SETUP_1TP      0x10    /* 1 port, TP */
-#define SETUP_1COAX    0x00    /* 1 port, Coax */
-#define SETUP_DRAM     0x02    /* Number of DRAMS on board */
-
-/*
-** EEPROM MANAGEMENT FLAGS
-*/
-#define MGMT_CCE       0x01    /* Custom Counters Enable */
-
-/*
-** EEPROM VERSIONS
-*/
-#define LeMAC           0x11
-#define LeMAC2          0x12
-
-/*
-** Miscellaneous
-*/
-
-#define EEPROM_WAIT_TIME 1000    /* Number of microseconds */
-#define EISA_EN         0x0001   /* Enable EISA bus buffers */
-
-#define HASH_TABLE_LEN   512     /* Bits */
-
-#define XCT 0x80                 /* Transmit Cut Through */
-#define PRELOAD 16               /* 4 long words */
-
-#define MASK_INTERRUPTS   1
-#define UNMASK_INTERRUPTS 0
-
-#define EEPROM_OFFSET(a) ((u_short)((u_long)(a)))
-
-/*
-** Include the IOCTL stuff
-*/
-#include <linux/sockios.h>
-
-#define        EWRK3IOCTL      SIOCDEVPRIVATE
-
-struct ewrk3_ioctl {
-       unsigned short cmd;                /* Command to run */
-       unsigned short len;                /* Length of the data buffer */
-       unsigned char  __user *data;       /* Pointer to the data buffer */
-};
-
-/*
-** Recognised commands for the driver
-*/
-#define EWRK3_GET_HWADDR       0x01 /* Get the hardware address */
-#define EWRK3_SET_HWADDR       0x02 /* Get the hardware address */
-#define EWRK3_SET_PROM         0x03 /* Set Promiscuous Mode */
-#define EWRK3_CLR_PROM         0x04 /* Clear Promiscuous Mode */
-#define EWRK3_SAY_BOO          0x05 /* Say "Boo!" to the kernel log file */
-#define EWRK3_GET_MCA          0x06 /* Get a multicast address */
-#define EWRK3_SET_MCA          0x07 /* Set a multicast address */
-#define EWRK3_CLR_MCA          0x08 /* Clear a multicast address */
-#define EWRK3_MCA_EN           0x09 /* Enable a multicast address group */
-#define EWRK3_GET_STATS        0x0a /* Get the driver statistics */
-#define EWRK3_CLR_STATS        0x0b /* Zero out the driver statistics */
-#define EWRK3_GET_CSR          0x0c /* Get the CSR Register contents */
-#define EWRK3_SET_CSR          0x0d /* Set the CSR Register contents */
-#define EWRK3_GET_EEPROM       0x0e /* Get the EEPROM contents */
-#define EWRK3_SET_EEPROM       0x0f /* Set the EEPROM contents */
-#define EWRK3_GET_CMR          0x10 /* Get the CMR Register contents */
-#define EWRK3_CLR_TX_CUT_THRU          0x11 /* Clear the TX cut through mode */
-#define EWRK3_SET_TX_CUT_THRU  0x12 /* Set the TX cut through mode */
index b5afe218c31be3644df3c7c527a3a574b45e8320..ee26ce78e270cabfb7acff61745b597703bab13c 100644 (file)
@@ -5,7 +5,7 @@
 config NET_VENDOR_DLINK
        bool "D-Link devices"
        default y
-       depends on PCI || PARPORT
+       depends on PCI
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
          and read the Ethernet-HOWTO, available from
@@ -18,36 +18,6 @@ config NET_VENDOR_DLINK
 
 if NET_VENDOR_DLINK
 
-config DE600
-       tristate "D-Link DE600 pocket adapter support"
-       depends on PARPORT
-       ---help---
-         This is a network (Ethernet) device which attaches to your parallel
-         port. Read <file:Documentation/networking/DLINK.txt> as well as the
-         Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, if you want to use
-         this. It is possible to have several devices share a single parallel
-         port and it is safe to compile the corresponding drivers into the
-         kernel.
-
-         To compile this driver as a module, choose M here: the module
-         will be called de600.
-
-config DE620
-       tristate "D-Link DE620 pocket adapter support"
-       depends on PARPORT
-       ---help---
-         This is a network (Ethernet) device which attaches to your parallel
-         port. Read <file:Documentation/networking/DLINK.txt> as well as the
-         Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, if you want to use
-         this. It is possible to have several devices share a single parallel
-         port and it is safe to compile the corresponding drivers into the
-         kernel.
-
-         To compile this driver as a module, choose M here: the module
-         will be called de620.
-
 config DL2K
        tristate "DL2000/TC902x-based Gigabit Ethernet support"
        depends on PCI
index c705eaa4f5b27f0426db53de19bb882cd539550e..40085f67157bde9be0634e1aad39050a6f0a8fcf 100644 (file)
@@ -2,7 +2,5 @@
 # Makefile for the D-Link network device drivers.
 #
 
-obj-$(CONFIG_DE600) += de600.o
-obj-$(CONFIG_DE620) += de620.o
 obj-$(CONFIG_DL2K) += dl2k.o
 obj-$(CONFIG_SUNDANCE) += sundance.o
diff --git a/drivers/net/ethernet/dlink/de600.c b/drivers/net/ethernet/dlink/de600.c
deleted file mode 100644 (file)
index 414f0ee..0000000
+++ /dev/null
@@ -1,529 +0,0 @@
-static const char version[] = "de600.c: $Revision: 1.41-2.5 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
-/*
- *     de600.c
- *
- *     Linux driver for the D-Link DE-600 Ethernet pocket adapter.
- *
- *     Portions (C) Copyright 1993, 1994 by Bjorn Ekwall
- *     The Author may be reached as bj0rn@blox.se
- *
- *     Based on adapter information gathered from DE600.ASM by D-Link Inc.,
- *     as included on disk C in the v.2.11 of PC/TCP from FTP Software.
- *     For DE600.asm:
- *             Portions (C) Copyright 1990 D-Link, Inc.
- *             Copyright, 1988-1992, Russell Nelson, Crynwr Software
- *
- *     Adapted to the sample network driver core for linux,
- *     written by: Donald Becker <becker@super.org>
- *             (Now at <becker@scyld.com>)
- *
- **************************************************************/
-/*
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2, or (at your option)
- *     any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **************************************************************/
-
-/* Add more time here if your adapter won't work OK: */
-#define DE600_SLOW_DOWN        udelay(delay_time)
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include "de600.h"
-
-static bool check_lost = true;
-module_param(check_lost, bool, 0);
-MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600");
-
-static unsigned int delay_time = 10;
-module_param(delay_time, int, 0);
-MODULE_PARM_DESC(delay_time, "DE-600 deley on I/O in microseconds");
-
-
-/*
- * D-Link driver variables:
- */
-
-static volatile int            rx_page;
-
-#define TX_PAGES 2
-static volatile int            tx_fifo[TX_PAGES];
-static volatile int            tx_fifo_in;
-static volatile int            tx_fifo_out;
-static volatile int            free_tx_pages = TX_PAGES;
-static int                     was_down;
-static DEFINE_SPINLOCK(de600_lock);
-
-static inline u8 de600_read_status(struct net_device *dev)
-{
-       u8 status;
-
-       outb_p(STATUS, DATA_PORT);
-       status = inb(STATUS_PORT);
-       outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
-
-       return status;
-}
-
-static inline u8 de600_read_byte(unsigned char type, struct net_device *dev)
-{
-       /* dev used by macros */
-       u8 lo;
-       outb_p((type), DATA_PORT);
-       lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
-       outb_p((type) | HI_NIBBLE, DATA_PORT);
-       return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
-}
-
-/*
- * Open/initialize the board.  This is called (in the current kernel)
- * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- */
-
-static int de600_open(struct net_device *dev)
-{
-       unsigned long flags;
-       int ret = request_irq(DE600_IRQ, de600_interrupt, 0, dev->name, dev);
-       if (ret) {
-               printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
-               return ret;
-       }
-       spin_lock_irqsave(&de600_lock, flags);
-       ret = adapter_init(dev);
-       spin_unlock_irqrestore(&de600_lock, flags);
-       return ret;
-}
-
-/*
- * The inverse routine to de600_open().
- */
-
-static int de600_close(struct net_device *dev)
-{
-       select_nic();
-       rx_page = 0;
-       de600_put_command(RESET);
-       de600_put_command(STOP_RESET);
-       de600_put_command(0);
-       select_prn();
-       free_irq(DE600_IRQ, dev);
-       return 0;
-}
-
-static inline void trigger_interrupt(struct net_device *dev)
-{
-       de600_put_command(FLIP_IRQ);
-       select_prn();
-       DE600_SLOW_DOWN;
-       select_nic();
-       de600_put_command(0);
-}
-
-/*
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-
-static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned long flags;
-       int     transmit_from;
-       int     len;
-       int     tickssofar;
-       u8      *buffer = skb->data;
-       int     i;
-
-       if (free_tx_pages <= 0) {       /* Do timeouts, to avoid hangs. */
-               tickssofar = jiffies - dev_trans_start(dev);
-               if (tickssofar < HZ/20)
-                       return NETDEV_TX_BUSY;
-               /* else */
-               printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
-               /* Restart the adapter. */
-               spin_lock_irqsave(&de600_lock, flags);
-               if (adapter_init(dev)) {
-                       spin_unlock_irqrestore(&de600_lock, flags);
-                       return NETDEV_TX_BUSY;
-               }
-               spin_unlock_irqrestore(&de600_lock, flags);
-       }
-
-       /* Start real output */
-       pr_debug("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages);
-
-       if ((len = skb->len) < RUNT)
-               len = RUNT;
-
-       spin_lock_irqsave(&de600_lock, flags);
-       select_nic();
-       tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
-       tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
-
-       if(check_lost)
-       {
-               /* This costs about 40 instructions per packet... */
-               de600_setup_address(NODE_ADDRESS, RW_ADDR);
-               de600_read_byte(READ_DATA, dev);
-               if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
-                       if (adapter_init(dev)) {
-                               spin_unlock_irqrestore(&de600_lock, flags);
-                               return NETDEV_TX_BUSY;
-                       }
-               }
-       }
-
-       de600_setup_address(transmit_from, RW_ADDR);
-       for (i = 0;  i < skb->len ; ++i, ++buffer)
-               de600_put_byte(*buffer);
-       for (; i < len; ++i)
-               de600_put_byte(0);
-
-       if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
-               dev->trans_start = jiffies;
-               netif_start_queue(dev); /* allow more packets into adapter */
-               /* Send page and generate a faked interrupt */
-               de600_setup_address(transmit_from, TX_ADDR);
-               de600_put_command(TX_ENABLE);
-       }
-       else {
-               if (free_tx_pages)
-                       netif_start_queue(dev);
-               else
-                       netif_stop_queue(dev);
-               select_prn();
-       }
-       spin_unlock_irqrestore(&de600_lock, flags);
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-
-static irqreturn_t de600_interrupt(int irq, void *dev_id)
-{
-       struct net_device       *dev = dev_id;
-       u8              irq_status;
-       int             retrig = 0;
-       int             boguscount = 0;
-
-       spin_lock(&de600_lock);
-
-       select_nic();
-       irq_status = de600_read_status(dev);
-
-       do {
-               pr_debug("de600_interrupt (%02X)\n", irq_status);
-
-               if (irq_status & RX_GOOD)
-                       de600_rx_intr(dev);
-               else if (!(irq_status & RX_BUSY))
-                       de600_put_command(RX_ENABLE);
-
-               /* Any transmission in progress? */
-               if (free_tx_pages < TX_PAGES)
-                       retrig = de600_tx_intr(dev, irq_status);
-               else
-                       retrig = 0;
-
-               irq_status = de600_read_status(dev);
-       } while ( (irq_status & RX_GOOD) || ((++boguscount < 100) && retrig) );
-       /*
-        * Yeah, it _looks_ like busy waiting, smells like busy waiting
-        * and I know it's not PC, but please, it will only occur once
-        * in a while and then only for a loop or so (< 1ms for sure!)
-        */
-
-       /* Enable adapter interrupts */
-       select_prn();
-       if (retrig)
-               trigger_interrupt(dev);
-       spin_unlock(&de600_lock);
-       return IRQ_HANDLED;
-}
-
-static int de600_tx_intr(struct net_device *dev, int irq_status)
-{
-       /*
-        * Returns 1 if tx still not done
-        */
-
-       /* Check if current transmission is done yet */
-       if (irq_status & TX_BUSY)
-               return 1; /* tx not done, try again */
-
-       /* else */
-       /* If last transmission OK then bump fifo index */
-       if (!(irq_status & TX_FAILED16)) {
-               tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
-               ++free_tx_pages;
-               dev->stats.tx_packets++;
-               netif_wake_queue(dev);
-       }
-
-       /* More to send, or resend last packet? */
-       if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) {
-               dev->trans_start = jiffies;
-               de600_setup_address(tx_fifo[tx_fifo_out], TX_ADDR);
-               de600_put_command(TX_ENABLE);
-               return 1;
-       }
-       /* else */
-
-       return 0;
-}
-
-/*
- * We have a good packet, get it out of the adapter.
- */
-static void de600_rx_intr(struct net_device *dev)
-{
-       struct sk_buff  *skb;
-       int             i;
-       int             read_from;
-       int             size;
-       unsigned char   *buffer;
-
-       /* Get size of received packet */
-       size = de600_read_byte(RX_LEN, dev);    /* low byte */
-       size += (de600_read_byte(RX_LEN, dev) << 8);    /* high byte */
-       size -= 4;      /* Ignore trailing 4 CRC-bytes */
-
-       /* Tell adapter where to store next incoming packet, enable receiver */
-       read_from = rx_page_adr();
-       next_rx_page();
-       de600_put_command(RX_ENABLE);
-
-       if ((size < 32)  ||  (size > 1535)) {
-               printk(KERN_WARNING "%s: Bogus packet size %d.\n", dev->name, size);
-               if (size > 10000)
-                       adapter_init(dev);
-               return;
-       }
-
-       skb = netdev_alloc_skb(dev, size + 2);
-       if (skb == NULL) {
-               printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
-               return;
-       }
-       /* else */
-
-       skb_reserve(skb,2);     /* Align */
-
-       /* 'skb->data' points to the start of sk_buff data area. */
-       buffer = skb_put(skb,size);
-
-       /* copy the packet into the buffer */
-       de600_setup_address(read_from, RW_ADDR);
-       for (i = size; i > 0; --i, ++buffer)
-               *buffer = de600_read_byte(READ_DATA, dev);
-
-       skb->protocol=eth_type_trans(skb,dev);
-
-       netif_rx(skb);
-
-       /* update stats */
-       dev->stats.rx_packets++; /* count all receives */
-       dev->stats.rx_bytes += size; /* count all received bytes */
-
-       /*
-        * If any worth-while packets have been received, netif_rx()
-        * will work on them when we get to the tasklets.
-        */
-}
-
-static const struct net_device_ops de600_netdev_ops = {
-       .ndo_open               = de600_open,
-       .ndo_stop               = de600_close,
-       .ndo_start_xmit         = de600_start_xmit,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-
-static struct net_device * __init de600_probe(void)
-{
-       int     i;
-       struct net_device *dev;
-       int err;
-
-       dev = alloc_etherdev(0);
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-
-       if (!request_region(DE600_IO, 3, "de600")) {
-               printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
-               err = -EBUSY;
-               goto out;
-       }
-
-       printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name);
-       /* Alpha testers must have the version number to report bugs. */
-       pr_debug("%s", version);
-
-       /* probe for adapter */
-       err = -ENODEV;
-       rx_page = 0;
-       select_nic();
-       (void)de600_read_status(dev);
-       de600_put_command(RESET);
-       de600_put_command(STOP_RESET);
-       if (de600_read_status(dev) & 0xf0) {
-               printk(": not at I/O %#3x.\n", DATA_PORT);
-               goto out1;
-       }
-
-       /*
-        * Maybe we found one,
-        * have to check if it is a D-Link DE-600 adapter...
-        */
-
-       /* Get the adapter ethernet address from the ROM */
-       de600_setup_address(NODE_ADDRESS, RW_ADDR);
-       for (i = 0; i < ETH_ALEN; i++) {
-               dev->dev_addr[i] = de600_read_byte(READ_DATA, dev);
-               dev->broadcast[i] = 0xff;
-       }
-
-       /* Check magic code */
-       if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) {
-               /* OK, install real address */
-               dev->dev_addr[0] = 0x00;
-               dev->dev_addr[1] = 0x80;
-               dev->dev_addr[2] = 0xc8;
-               dev->dev_addr[3] &= 0x0f;
-               dev->dev_addr[3] |= 0x70;
-       } else {
-               printk(" not identified in the printer port\n");
-               goto out1;
-       }
-
-       printk(", Ethernet Address: %pM\n", dev->dev_addr);
-
-       dev->netdev_ops = &de600_netdev_ops;
-
-       dev->flags&=~IFF_MULTICAST;
-
-       select_prn();
-
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-
-       return dev;
-
-out1:
-       release_region(DE600_IO, 3);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static int adapter_init(struct net_device *dev)
-{
-       int     i;
-
-       select_nic();
-       rx_page = 0; /* used by RESET */
-       de600_put_command(RESET);
-       de600_put_command(STOP_RESET);
-
-       /* Check if it is still there... */
-       /* Get the some bytes of the adapter ethernet address from the ROM */
-       de600_setup_address(NODE_ADDRESS, RW_ADDR);
-       de600_read_byte(READ_DATA, dev);
-       if ((de600_read_byte(READ_DATA, dev) != 0xde) ||
-           (de600_read_byte(READ_DATA, dev) != 0x15)) {
-       /* was: if (de600_read_status(dev) & 0xf0) { */
-               printk("Something has happened to the DE-600!  Please check it and do a new ifconfig!\n");
-               /* Goodbye, cruel world... */
-               dev->flags &= ~IFF_UP;
-               de600_close(dev);
-               was_down = 1;
-               netif_stop_queue(dev); /* Transmit busy...  */
-               return 1; /* failed */
-       }
-
-       if (was_down) {
-               printk(KERN_INFO "%s: Thanks, I feel much better now!\n", dev->name);
-               was_down = 0;
-       }
-
-       tx_fifo_in = 0;
-       tx_fifo_out = 0;
-       free_tx_pages = TX_PAGES;
-
-
-       /* set the ether address. */
-       de600_setup_address(NODE_ADDRESS, RW_ADDR);
-       for (i = 0; i < ETH_ALEN; i++)
-               de600_put_byte(dev->dev_addr[i]);
-
-       /* where to start saving incoming packets */
-       rx_page = RX_BP | RX_BASE_PAGE;
-       de600_setup_address(MEM_4K, RW_ADDR);
-       /* Enable receiver */
-       de600_put_command(RX_ENABLE);
-       select_prn();
-
-       netif_start_queue(dev);
-
-       return 0; /* OK */
-}
-
-static struct net_device *de600_dev;
-
-static int __init de600_init(void)
-{
-       de600_dev = de600_probe();
-       if (IS_ERR(de600_dev))
-               return PTR_ERR(de600_dev);
-       return 0;
-}
-
-static void __exit de600_exit(void)
-{
-       unregister_netdev(de600_dev);
-       release_region(DE600_IO, 3);
-       free_netdev(de600_dev);
-}
-
-module_init(de600_init);
-module_exit(de600_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de600.h b/drivers/net/ethernet/dlink/de600.h
deleted file mode 100644 (file)
index e80ecba..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/**************************************************
- *                                                *
- * Definition of D-Link Ethernet Pocket adapter   *
- *                                                *
- **************************************************/
-/*
- * D-Link Ethernet pocket adapter ports
- */
-/*
- * OK, so I'm cheating, but there are an awful lot of
- * reads and writes in order to get anything in and out
- * of the DE-600 with 4 bits at a time in the parallel port,
- * so every saved instruction really helps :-)
- */
-
-#ifndef DE600_IO
-#define DE600_IO       0x378
-#endif
-
-#define DATA_PORT      (DE600_IO)
-#define STATUS_PORT    (DE600_IO + 1)
-#define COMMAND_PORT   (DE600_IO + 2)
-
-#ifndef DE600_IRQ
-#define DE600_IRQ      7
-#endif
-/*
- * It really should look like this, and autoprobing as well...
- *
-#define DATA_PORT      (dev->base_addr + 0)
-#define STATUS_PORT    (dev->base_addr + 1)
-#define COMMAND_PORT   (dev->base_addr + 2)
-#define DE600_IRQ      dev->irq
- */
-
-/*
- * D-Link COMMAND_PORT commands
- */
-#define SELECT_NIC     0x04 /* select Network Interface Card */
-#define SELECT_PRN     0x1c /* select Printer */
-#define NML_PRN                0xec /* normal Printer situation */
-#define IRQEN          0x10 /* enable IRQ line */
-
-/*
- * D-Link STATUS_PORT
- */
-#define RX_BUSY                0x80
-#define RX_GOOD                0x40
-#define TX_FAILED16    0x10
-#define TX_BUSY                0x08
-
-/*
- * D-Link DATA_PORT commands
- * command in low 4 bits
- * data in high 4 bits
- * select current data nibble with HI_NIBBLE bit
- */
-#define WRITE_DATA     0x00 /* write memory */
-#define READ_DATA      0x01 /* read memory */
-#define STATUS         0x02 /* read  status register */
-#define COMMAND                0x03 /* write command register (see COMMAND below) */
-#define NULL_COMMAND   0x04 /* null command */
-#define RX_LEN         0x05 /* read  received packet length */
-#define TX_ADDR                0x06 /* set adapter transmit memory address */
-#define RW_ADDR                0x07 /* set adapter read/write memory address */
-#define HI_NIBBLE      0x08 /* read/write the high nibble of data,
-                               or-ed with rest of command */
-
-/*
- * command register, accessed through DATA_PORT with low bits = COMMAND
- */
-#define RX_ALL         0x01 /* PROMISCUOUS */
-#define RX_BP          0x02 /* default: BROADCAST & PHYSICAL ADDRESS */
-#define RX_MBP         0x03 /* MULTICAST, BROADCAST & PHYSICAL ADDRESS */
-
-#define TX_ENABLE      0x04 /* bit 2 */
-#define RX_ENABLE      0x08 /* bit 3 */
-
-#define RESET          0x80 /* set bit 7 high */
-#define STOP_RESET     0x00 /* set bit 7 low */
-
-/*
- * data to command register
- * (high 4 bits in write to DATA_PORT)
- */
-#define RX_PAGE2_SELECT        0x10 /* bit 4, only 2 pages to select */
-#define RX_BASE_PAGE   0x20 /* bit 5, always set when specifying RX_ADDR */
-#define FLIP_IRQ       0x40 /* bit 6 */
-
-/*
- * D-Link adapter internal memory:
- *
- * 0-2K 1:st transmit page (send from pointer up to 2K)
- * 2-4K        2:nd transmit page (send from pointer up to 4K)
- *
- * 4-6K 1:st receive page (data from 4K upwards)
- * 6-8K 2:nd receive page (data from 6K upwards)
- *
- * 8K+ Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
- */
-#define MEM_2K         0x0800 /* 2048 */
-#define MEM_4K         0x1000 /* 4096 */
-#define MEM_6K         0x1800 /* 6144 */
-#define NODE_ADDRESS   0x2000 /* 8192 */
-
-#define RUNT 60                /* Too small Ethernet packet */
-
-/**************************************************
- *                                                *
- *             End of definition                  *
- *                                                *
- **************************************************/
-
-/*
- * Index to functions, as function prototypes.
- */
-/* Routines used internally. (See "convenience macros") */
-static u8      de600_read_status(struct net_device *dev);
-static u8      de600_read_byte(unsigned char type, struct net_device *dev);
-
-/* Put in the device structure. */
-static int     de600_open(struct net_device *dev);
-static int     de600_close(struct net_device *dev);
-static int     de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de600_interrupt(int irq, void *dev_id);
-static int     de600_tx_intr(struct net_device *dev, int irq_status);
-static void    de600_rx_intr(struct net_device *dev);
-
-/* Initialization */
-static void    trigger_interrupt(struct net_device *dev);
-static int     adapter_init(struct net_device *dev);
-
-/*
- * Convenience macros/functions for D-Link adapter
- */
-
-#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN
-#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN
-
-/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
-#define de600_put_byte(data) ( \
-       outb_p(((data) << 4)   | WRITE_DATA            , DATA_PORT), \
-       outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
-
-/*
- * The first two outb_p()'s below could perhaps be deleted if there
- * would be more delay in the last two. Not certain about it yet...
- */
-#define de600_put_command(cmd) ( \
-       outb_p(( rx_page        << 4)   | COMMAND            , DATA_PORT), \
-       outb_p(( rx_page        & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
-       outb_p(((rx_page | cmd) << 4)   | COMMAND            , DATA_PORT), \
-       outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
-
-#define de600_setup_address(addr,type) ( \
-       outb_p((((addr) << 4) & 0xf0) | type            , DATA_PORT), \
-       outb_p(( (addr)       & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
-       outb_p((((addr) >> 4) & 0xf0) | type            , DATA_PORT), \
-       outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
-
-#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
-
-/* Flip bit, only 2 pages */
-#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
-
-#define tx_page_adr(a) (((a) + 1) * MEM_2K)
diff --git a/drivers/net/ethernet/dlink/de620.c b/drivers/net/ethernet/dlink/de620.c
deleted file mode 100644 (file)
index 2e2bc60..0000000
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- *     de620.c $Revision: 1.40 $ BETA
- *
- *
- *     Linux driver for the D-Link DE-620 Ethernet pocket adapter.
- *
- *     Portions (C) Copyright 1993, 1994 by Bjorn Ekwall <bj0rn@blox.se>
- *
- *     Based on adapter information gathered from DOS packetdriver
- *     sources from D-Link Inc:  (Special thanks to Henry Ngai of D-Link.)
- *             Portions (C) Copyright D-Link SYSTEM Inc. 1991, 1992
- *             Copyright, 1988, Russell Nelson, Crynwr Software
- *
- *     Adapted to the sample network driver core for linux,
- *     written by: Donald Becker <becker@super.org>
- *             (Now at <becker@scyld.com>)
- *
- *     Valuable assistance from:
- *             J. Joshua Kopper <kopper@rtsg.mot.com>
- *             Olav Kvittem <Olav.Kvittem@uninett.no>
- *             Germano Caronni <caronni@nessie.cs.id.ethz.ch>
- *             Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
- *
- *****************************************************************************/
-/*
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2, or (at your option)
- *     any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *****************************************************************************/
-static const char version[] =
-       "de620.c: $Revision: 1.40 $,  Bjorn Ekwall <bj0rn@blox.se>\n";
-
-/***********************************************************************
- *
- * "Tuning" section.
- *
- * Compile-time options: (see below for descriptions)
- * -DDE620_IO=0x378    (lpt1)
- * -DDE620_IRQ=7       (lpt1)
- * -DSHUTDOWN_WHEN_LOST
- * -DCOUNT_LOOPS
- * -DLOWSPEED
- * -DREAD_DELAY
- * -DWRITE_DELAY
- */
-
-/*
- * This driver assumes that the printer port is a "normal",
- * dumb, uni-directional port!
- * If your port is "fancy" in any way, please try to set it to "normal"
- * with your BIOS setup.  I have no access to machines with bi-directional
- * ports, so I can't test such a driver :-(
- * (Yes, I _know_ it is possible to use DE620 with bidirectional ports...)
- *
- * There are some clones of DE620 out there, with different names.
- * If the current driver does not recognize a clone, try to change
- * the following #define to:
- *
- * #define DE620_CLONE 1
- */
-#define DE620_CLONE 0
-
-/*
- * If the adapter has problems with high speeds, enable this #define
- * otherwise full printerport speed will be attempted.
- *
- * You can tune the READ_DELAY/WRITE_DELAY below if you enable LOWSPEED
- *
-#define LOWSPEED
- */
-
-#ifndef READ_DELAY
-#define READ_DELAY 100 /* adapter internal read delay in 100ns units */
-#endif
-
-#ifndef WRITE_DELAY
-#define WRITE_DELAY 100        /* adapter internal write delay in 100ns units */
-#endif
-
-/*
- * Enable this #define if you want the adapter to do a "ifconfig down" on
- * itself when we have detected that something is possibly wrong with it.
- * The default behaviour is to retry with "adapter_init()" until success.
- * This should be used for debugging purposes only.
- *
-#define SHUTDOWN_WHEN_LOST
- */
-
-#ifdef LOWSPEED
-/*
- * Enable this #define if you want to see debugging output that show how long
- * we have to wait before the DE-620 is ready for the next read/write/command.
- *
-#define COUNT_LOOPS
- */
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-/* Constant definitions for the DE-620 registers, commands and bits */
-#include "de620.h"
-
-typedef unsigned char byte;
-
-/*******************************************************
- *                                                     *
- * Definition of D-Link DE-620 Ethernet Pocket adapter *
- * See also "de620.h"                                  *
- *                                                     *
- *******************************************************/
-#ifndef DE620_IO /* Compile-time configurable */
-#define DE620_IO 0x378
-#endif
-
-#ifndef DE620_IRQ /* Compile-time configurable */
-#define DE620_IRQ      7
-#endif
-
-#define DATA_PORT      (dev->base_addr)
-#define STATUS_PORT    (dev->base_addr + 1)
-#define COMMAND_PORT   (dev->base_addr + 2)
-
-#define RUNT 60                /* Too small Ethernet packet */
-#define GIANT 1514     /* largest legal size packet, no fcs */
-
-/*
- * Force media with insmod:
- *     insmod de620.o bnc=1
- * or
- *     insmod de620.o utp=1
- *
- * Force io and/or irq with insmod:
- *     insmod de620.o io=0x378 irq=7
- *
- * Make a clone skip the Ethernet-address range check:
- *     insmod de620.o clone=1
- */
-static int bnc;
-static int utp;
-static int io  = DE620_IO;
-static int irq = DE620_IRQ;
-static int clone = DE620_CLONE;
-
-static spinlock_t de620_lock;
-
-module_param(bnc, int, 0);
-module_param(utp, int, 0);
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(clone, int, 0);
-MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)");
-MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)");
-MODULE_PARM_DESC(io, "DE-620 I/O base address,required");
-MODULE_PARM_DESC(irq, "DE-620 IRQ number,required");
-MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)");
-
-/***********************************************
- *                                             *
- * Index to functions, as function prototypes. *
- *                                             *
- ***********************************************/
-
-/*
- * Routines used internally. (See also "convenience macros.. below")
- */
-
-/* Put in the device structure. */
-static int     de620_open(struct net_device *);
-static int     de620_close(struct net_device *);
-static void    de620_set_multicast_list(struct net_device *);
-static int     de620_start_xmit(struct sk_buff *, struct net_device *);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de620_interrupt(int, void *);
-static int     de620_rx_intr(struct net_device *);
-
-/* Initialization */
-static int     adapter_init(struct net_device *);
-static int     read_eeprom(struct net_device *);
-
-
-/*
- * D-Link driver variables:
- */
-#define SCR_DEF NIBBLEMODE |INTON | SLEEP | AUTOTX
-#define        TCR_DEF RXPB                    /* not used: | TXSUCINT | T16INT */
-#define DE620_RX_START_PAGE 12         /* 12 pages (=3k) reserved for tx */
-#define DEF_NIC_CMD IRQEN | ICEN | DS1
-
-static volatile byte   NIC_Cmd;
-static volatile byte   next_rx_page;
-static byte            first_rx_page;
-static byte            last_rx_page;
-static byte            EIPRegister;
-
-static struct nic {
-       byte    NodeID[6];
-       byte    RAM_Size;
-       byte    Model;
-       byte    Media;
-       byte    SCR;
-} nic_data;
-
-/**********************************************************
- *                                                        *
- * Convenience macros/functions for D-Link DE-620 adapter *
- *                                                        *
- **********************************************************/
-#define de620_tx_buffs(dd) (inb(STATUS_PORT) & (TXBF0 | TXBF1))
-#define de620_flip_ds(dd) NIC_Cmd ^= DS0 | DS1; outb(NIC_Cmd, COMMAND_PORT);
-
-/* Check for ready-status, and return a nibble (high 4 bits) for data input */
-#ifdef COUNT_LOOPS
-static int tot_cnt;
-#endif
-static inline byte
-de620_ready(struct net_device *dev)
-{
-       byte value;
-       register short int cnt = 0;
-
-       while ((((value = inb(STATUS_PORT)) & READY) == 0) && (cnt <= 1000))
-               ++cnt;
-
-#ifdef COUNT_LOOPS
-       tot_cnt += cnt;
-#endif
-       return value & 0xf0; /* nibble */
-}
-
-static inline void
-de620_send_command(struct net_device *dev, byte cmd)
-{
-       de620_ready(dev);
-       if (cmd == W_DUMMY)
-               outb(NIC_Cmd, COMMAND_PORT);
-
-       outb(cmd, DATA_PORT);
-
-       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-       de620_ready(dev);
-       outb(NIC_Cmd, COMMAND_PORT);
-}
-
-static inline void
-de620_put_byte(struct net_device *dev, byte value)
-{
-       /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
-       de620_ready(dev);
-       outb(value, DATA_PORT);
-       de620_flip_ds(dev);
-}
-
-static inline byte
-de620_read_byte(struct net_device *dev)
-{
-       byte value;
-
-       /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
-       value = de620_ready(dev); /* High nibble */
-       de620_flip_ds(dev);
-       value |= de620_ready(dev) >> 4; /* Low nibble */
-       return value;
-}
-
-static inline void
-de620_write_block(struct net_device *dev, byte *buffer, int count, int pad)
-{
-#ifndef LOWSPEED
-       byte uflip = NIC_Cmd ^ (DS0 | DS1);
-       byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
-       int bytes = count;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
-#ifdef COUNT_LOOPS
-       tot_cnt = 0;
-#endif /* COUNT_LOOPS */
-       /* No further optimization useful, the limit is in the adapter. */
-       for ( ; count > 0; --count, ++buffer) {
-               de620_put_byte(dev,*buffer);
-       }
-       for ( count = pad ; count > 0; --count, ++buffer) {
-               de620_put_byte(dev, 0);
-       }
-       de620_send_command(dev,W_DUMMY);
-#ifdef COUNT_LOOPS
-       /* trial debug output: loops per byte in de620_ready() */
-       printk("WRITE(%d)\n", tot_cnt/((bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
-       for ( ; count > 0; count -=2) {
-               outb(*buffer++, DATA_PORT);
-               outb(uflip, COMMAND_PORT);
-               outb(*buffer++, DATA_PORT);
-               outb(dflip, COMMAND_PORT);
-       }
-       de620_send_command(dev,W_DUMMY);
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_read_block(struct net_device *dev, byte *data, int count)
-{
-#ifndef LOWSPEED
-       byte value;
-       byte uflip = NIC_Cmd ^ (DS0 | DS1);
-       byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
-       int bytes = count;
-
-       tot_cnt = 0;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
-       /* No further optimization useful, the limit is in the adapter. */
-       while (count-- > 0) {
-               *data++ = de620_read_byte(dev);
-               de620_flip_ds(dev);
-       }
-#ifdef COUNT_LOOPS
-       /* trial debug output: loops per byte in de620_ready() */
-       printk("READ(%d)\n", tot_cnt/(2*(bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
-       while (count-- > 0) {
-               value = inb(STATUS_PORT) & 0xf0; /* High nibble */
-               outb(uflip, COMMAND_PORT);
-               *data++ = value | inb(STATUS_PORT) >> 4; /* Low nibble */
-               outb(dflip , COMMAND_PORT);
-       }
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_set_delay(struct net_device *dev)
-{
-       de620_ready(dev);
-       outb(W_DFR, DATA_PORT);
-       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
-       de620_ready(dev);
-#ifdef LOWSPEED
-       outb(WRITE_DELAY, DATA_PORT);
-#else
-       outb(0, DATA_PORT);
-#endif
-       de620_flip_ds(dev);
-
-       de620_ready(dev);
-#ifdef LOWSPEED
-       outb(READ_DELAY, DATA_PORT);
-#else
-       outb(0, DATA_PORT);
-#endif
-       de620_flip_ds(dev);
-}
-
-static inline void
-de620_set_register(struct net_device *dev, byte reg, byte value)
-{
-       de620_ready(dev);
-       outb(reg, DATA_PORT);
-       outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
-       de620_put_byte(dev, value);
-}
-
-static inline byte
-de620_get_register(struct net_device *dev, byte reg)
-{
-       byte value;
-
-       de620_send_command(dev,reg);
-       value = de620_read_byte(dev);
-       de620_send_command(dev,W_DUMMY);
-
-       return value;
-}
-
-/*********************************************************************
- *
- * Open/initialize the board.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- *
- */
-static int de620_open(struct net_device *dev)
-{
-       int ret = request_irq(dev->irq, de620_interrupt, 0, dev->name, dev);
-       if (ret) {
-               printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
-               return ret;
-       }
-
-       if (adapter_init(dev)) {
-               ret = -EIO;
-               goto out_free_irq;
-       }
-
-       netif_start_queue(dev);
-       return 0;
-
-out_free_irq:
-       free_irq(dev->irq, dev);
-       return ret;
-}
-
-/************************************************
- *
- * The inverse routine to de620_open().
- *
- */
-
-static int de620_close(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       /* disable recv */
-       de620_set_register(dev, W_TCR, RXOFF);
-       free_irq(dev->irq, dev);
-       return 0;
-}
-
-/*********************************************
- *
- * Set or clear the multicast filter for this adaptor.
- * (no real multicast implemented for the DE-620, but she can be promiscuous...)
- *
- */
-
-static void de620_set_multicast_list(struct net_device *dev)
-{
-       if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
-       { /* Enable promiscuous mode */
-               de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
-       }
-       else
-       { /* Disable promiscuous mode, use normal mode */
-               de620_set_register(dev, W_TCR, TCR_DEF);
-       }
-}
-
-/*******************************************************
- *
- * Handle timeouts on transmit
- */
-
-static void de620_timeout(struct net_device *dev)
-{
-       printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, "network cable problem");
-       /* Restart the adapter. */
-       if (!adapter_init(dev)) /* maybe close it */
-               netif_wake_queue(dev);
-}
-
-/*******************************************************
- *
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned long flags;
-       int len;
-       byte *buffer = skb->data;
-       byte using_txbuf;
-
-       using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
-
-       netif_stop_queue(dev);
-
-
-       if ((len = skb->len) < RUNT)
-               len = RUNT;
-       if (len & 1) /* send an even number of bytes */
-               ++len;
-
-       /* Start real output */
-
-       spin_lock_irqsave(&de620_lock, flags);
-       pr_debug("de620_start_xmit: len=%d, bufs 0x%02x\n",
-               (int)skb->len, using_txbuf);
-
-       /* select a free tx buffer. if there is one... */
-       switch (using_txbuf) {
-       default: /* both are free: use TXBF0 */
-       case TXBF1: /* use TXBF0 */
-               de620_send_command(dev,W_CR | RW0);
-               using_txbuf |= TXBF0;
-               break;
-
-       case TXBF0: /* use TXBF1 */
-               de620_send_command(dev,W_CR | RW1);
-               using_txbuf |= TXBF1;
-               break;
-
-       case (TXBF0 | TXBF1): /* NONE!!! */
-               printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name);
-               spin_unlock_irqrestore(&de620_lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-       de620_write_block(dev, buffer, skb->len, len-skb->len);
-
-       if(!(using_txbuf == (TXBF0 | TXBF1)))
-               netif_wake_queue(dev);
-
-       dev->stats.tx_packets++;
-       spin_unlock_irqrestore(&de620_lock, flags);
-       dev_kfree_skb (skb);
-       return NETDEV_TX_OK;
-}
-
-/*****************************************************
- *
- * Handle the network interface interrupts.
- *
- */
-static irqreturn_t
-de620_interrupt(int irq_in, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       byte irq_status;
-       int bogus_count = 0;
-       int again = 0;
-
-       spin_lock(&de620_lock);
-
-       /* Read the status register (_not_ the status port) */
-       irq_status = de620_get_register(dev, R_STS);
-
-       pr_debug("de620_interrupt (%2.2X)\n", irq_status);
-
-       if (irq_status & RXGOOD) {
-               do {
-                       again = de620_rx_intr(dev);
-                       pr_debug("again=%d\n", again);
-               }
-               while (again && (++bogus_count < 100));
-       }
-
-       if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
-               netif_wake_queue(dev);
-
-       spin_unlock(&de620_lock);
-       return IRQ_HANDLED;
-}
-
-/**************************************
- *
- * Get a packet from the adapter
- *
- * Send it "upstairs"
- *
- */
-static int de620_rx_intr(struct net_device *dev)
-{
-       struct header_buf {
-               byte            status;
-               byte            Rx_NextPage;
-               unsigned short  Rx_ByteCount;
-       } header_buf;
-       struct sk_buff *skb;
-       int size;
-       byte *buffer;
-       byte pagelink;
-       byte curr_page;
-
-       pr_debug("de620_rx_intr: next_rx_page = %d\n", next_rx_page);
-
-       /* Tell the adapter that we are going to read data, and from where */
-       de620_send_command(dev, W_CR | RRN);
-       de620_set_register(dev, W_RSA1, next_rx_page);
-       de620_set_register(dev, W_RSA0, 0);
-
-       /* Deep breath, and away we goooooo */
-       de620_read_block(dev, (byte *)&header_buf, sizeof(struct header_buf));
-       pr_debug("page status=0x%02x, nextpage=%d, packetsize=%d\n",
-               header_buf.status, header_buf.Rx_NextPage,
-               header_buf.Rx_ByteCount);
-
-       /* Plausible page header? */
-       pagelink = header_buf.Rx_NextPage;
-       if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
-               /* Ouch... Forget it! Skip all and start afresh... */
-               printk(KERN_WARNING "%s: Ring overrun? Restoring...\n", dev->name);
-               /* You win some, you lose some. And sometimes plenty... */
-               adapter_init(dev);
-               netif_wake_queue(dev);
-               dev->stats.rx_over_errors++;
-               return 0;
-       }
-
-       /* OK, this look good, so far. Let's see if it's consistent... */
-       /* Let's compute the start of the next packet, based on where we are */
-       pagelink = next_rx_page +
-               ((header_buf.Rx_ByteCount + (4 - 1 + 0x100)) >> 8);
-
-       /* Are we going to wrap around the page counter? */
-       if (pagelink > last_rx_page)
-               pagelink -= (last_rx_page - first_rx_page + 1);
-
-       /* Is the _computed_ next page number equal to what the adapter says? */
-       if (pagelink != header_buf.Rx_NextPage) {
-               /* Naah, we'll skip this packet. Probably bogus data as well */
-               printk(KERN_WARNING "%s: Page link out of sync! Restoring...\n", dev->name);
-               next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
-               de620_send_command(dev, W_DUMMY);
-               de620_set_register(dev, W_NPRF, next_rx_page);
-               dev->stats.rx_over_errors++;
-               return 0;
-       }
-       next_rx_page = pagelink;
-
-       size = header_buf.Rx_ByteCount - 4;
-       if ((size < RUNT) || (GIANT < size)) {
-               printk(KERN_WARNING "%s: Illegal packet size: %d!\n", dev->name, size);
-       }
-       else { /* Good packet? */
-               skb = netdev_alloc_skb(dev, size + 2);
-               if (skb == NULL) { /* Yeah, but no place to put it... */
-                       printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
-                       dev->stats.rx_dropped++;
-               }
-               else { /* Yep! Go get it! */
-                       skb_reserve(skb,2);     /* Align */
-                       /* skb->data points to the start of sk_buff data area */
-                       buffer = skb_put(skb,size);
-                       /* copy the packet into the buffer */
-                       de620_read_block(dev, buffer, size);
-                       pr_debug("Read %d bytes\n", size);
-                       skb->protocol=eth_type_trans(skb,dev);
-                       netif_rx(skb); /* deliver it "upstairs" */
-                       /* count all receives */
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += size;
-               }
-       }
-
-       /* Let's peek ahead to see if we have read the last current packet */
-       /* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */
-       curr_page = de620_get_register(dev, R_CPR);
-       de620_set_register(dev, W_NPRF, next_rx_page);
-       pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page);
-
-       return next_rx_page != curr_page; /* That was slightly tricky... */
-}
-
-/*********************************************
- *
- * Reset the adapter to a known state
- *
- */
-static int adapter_init(struct net_device *dev)
-{
-       int i;
-       static int was_down;
-
-       if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */
-               EIPRegister = NCTL0;
-               if (nic_data.Media != 1)
-                       EIPRegister |= NIS0;    /* not BNC */
-       }
-       else if (nic_data.Model == 2) { /* UTP */
-               EIPRegister = NCTL0 | NIS0;
-       }
-
-       if (utp)
-               EIPRegister = NCTL0 | NIS0;
-       if (bnc)
-               EIPRegister = NCTL0;
-
-       de620_send_command(dev, W_CR | RNOP | CLEAR);
-       de620_send_command(dev, W_CR | RNOP);
-
-       de620_set_register(dev, W_SCR, SCR_DEF);
-       /* disable recv to wait init */
-       de620_set_register(dev, W_TCR, RXOFF);
-
-       /* Set the node ID in the adapter */
-       for (i = 0; i < 6; ++i) { /* W_PARn = 0xaa + n */
-               de620_set_register(dev, W_PAR0 + i, dev->dev_addr[i]);
-       }
-
-       de620_set_register(dev, W_EIP, EIPRegister);
-
-       next_rx_page = first_rx_page = DE620_RX_START_PAGE;
-       if (nic_data.RAM_Size)
-               last_rx_page = nic_data.RAM_Size - 1;
-       else /* 64k RAM */
-               last_rx_page = 255;
-
-       de620_set_register(dev, W_SPR, first_rx_page); /* Start Page Register*/
-       de620_set_register(dev, W_EPR, last_rx_page);  /* End Page Register */
-       de620_set_register(dev, W_CPR, first_rx_page);/*Current Page Register*/
-       de620_send_command(dev, W_NPR | first_rx_page); /* Next Page Register*/
-       de620_send_command(dev, W_DUMMY);
-       de620_set_delay(dev);
-
-       /* Final sanity check: Anybody out there? */
-       /* Let's hope some bits from the statusregister make a good check */
-#define CHECK_MASK (  0 | TXSUC |  T16  |  0  | RXCRC | RXSHORT |  0  |  0  )
-#define CHECK_OK   (  0 |   0   |  0    |  0  |   0   |   0     |  0  |  0  )
-        /* success:   X     0      0       X      0       0        X     X  */
-        /* ignore:   EEDI                RXGOOD                   COLS  LNKS*/
-
-       if (((i = de620_get_register(dev, R_STS)) & CHECK_MASK) != CHECK_OK) {
-               printk(KERN_ERR "%s: Something has happened to the DE-620!  Please check it"
-#ifdef SHUTDOWN_WHEN_LOST
-                       " and do a new ifconfig"
-#endif
-                       "! (%02x)\n", dev->name, i);
-#ifdef SHUTDOWN_WHEN_LOST
-               /* Goodbye, cruel world... */
-               dev->flags &= ~IFF_UP;
-               de620_close(dev);
-#endif
-               was_down = 1;
-               return 1; /* failed */
-       }
-       if (was_down) {
-               printk(KERN_WARNING "%s: Thanks, I feel much better now!\n", dev->name);
-               was_down = 0;
-       }
-
-       /* All OK, go ahead... */
-       de620_set_register(dev, W_TCR, TCR_DEF);
-
-       return 0; /* all ok */
-}
-
-static const struct net_device_ops de620_netdev_ops = {
-       .ndo_open               = de620_open,
-       .ndo_stop               = de620_close,
-       .ndo_start_xmit         = de620_start_xmit,
-       .ndo_tx_timeout         = de620_timeout,
-       .ndo_set_rx_mode        = de620_set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/******************************************************************************
- *
- * Only start-up code below
- *
- */
-/****************************************
- *
- * Check if there is a DE-620 connected
- */
-struct net_device * __init de620_probe(int unit)
-{
-       byte checkbyte = 0xa5;
-       struct net_device *dev;
-       int err = -ENOMEM;
-       int i;
-
-       dev = alloc_etherdev(0);
-       if (!dev)
-               goto out;
-
-       spin_lock_init(&de620_lock);
-
-       /*
-        * This is where the base_addr and irq gets set.
-        * Tunable at compile-time and insmod-time
-        */
-       dev->base_addr = io;
-       dev->irq       = irq;
-
-       /* allow overriding parameters on command line */
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       pr_debug("%s", version);
-
-       printk(KERN_INFO "D-Link DE-620 pocket adapter");
-
-       if (!request_region(dev->base_addr, 3, "de620")) {
-               printk(" io 0x%3lX, which is busy.\n", dev->base_addr);
-               err = -EBUSY;
-               goto out1;
-       }
-
-       /* Initially, configure basic nibble mode, so we can read the EEPROM */
-       NIC_Cmd = DEF_NIC_CMD;
-       de620_set_register(dev, W_EIP, EIPRegister);
-
-       /* Anybody out there? */
-       de620_set_register(dev, W_CPR, checkbyte);
-       checkbyte = de620_get_register(dev, R_CPR);
-
-       if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) {
-               printk(" not identified in the printer port\n");
-               err = -ENODEV;
-               goto out2;
-       }
-
-       /* else, got it! */
-       dev->dev_addr[0] = nic_data.NodeID[0];
-       for (i = 1; i < ETH_ALEN; i++) {
-               dev->dev_addr[i] = nic_data.NodeID[i];
-               dev->broadcast[i] = 0xff;
-       }
-
-       printk(", Ethernet Address: %pM", dev->dev_addr);
-
-       printk(" (%dk RAM,",
-               (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
-
-       if (nic_data.Media == 1)
-               printk(" BNC)\n");
-       else
-               printk(" UTP)\n");
-
-       dev->netdev_ops = &de620_netdev_ops;
-       dev->watchdog_timeo     = HZ*2;
-
-       /* base_addr and irq are already set, see above! */
-
-       /* dump eeprom */
-       pr_debug("\nEEPROM contents:\n"
-               "RAM_Size = 0x%02X\n"
-               "NodeID = %pM\n"
-               "Model = %d\n"
-               "Media = %d\n"
-               "SCR = 0x%02x\n", nic_data.RAM_Size, nic_data.NodeID,
-               nic_data.Model, nic_data.Media, nic_data.SCR);
-
-       err = register_netdev(dev);
-       if (err)
-               goto out2;
-       return dev;
-
-out2:
-       release_region(dev->base_addr, 3);
-out1:
-       free_netdev(dev);
-out:
-       return ERR_PTR(err);
-}
-
-/**********************************
- *
- * Read info from on-board EEPROM
- *
- * Note: Bitwise serial I/O to/from the EEPROM vi the status _register_!
- */
-#define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister);
-
-static unsigned short __init ReadAWord(struct net_device *dev, int from)
-{
-       unsigned short data;
-       int nbits;
-
-       /* cs   [__~~] SET SEND STATE */
-       /* di   [____]                */
-       /* sck  [_~~_]                */
-       sendit(dev, 0); sendit(dev, 1); sendit(dev, 5); sendit(dev, 4);
-
-       /* Send the 9-bit address from where we want to read the 16-bit word */
-       for (nbits = 9; nbits > 0; --nbits, from <<= 1) {
-               if (from & 0x0100) { /* bit set? */
-                       /* cs    [~~~~] SEND 1 */
-                       /* di    [~~~~]        */
-                       /* sck   [_~~_]        */
-                       sendit(dev, 6); sendit(dev, 7); sendit(dev, 7); sendit(dev, 6);
-               }
-               else {
-                       /* cs    [~~~~] SEND 0 */
-                       /* di    [____]        */
-                       /* sck   [_~~_]        */
-                       sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
-               }
-       }
-
-       /* Shift in the 16-bit word. The bits appear serially in EEDI (=0x80) */
-       for (data = 0, nbits = 16; nbits > 0; --nbits) {
-               /* cs    [~~~~] SEND 0 */
-               /* di    [____]        */
-               /* sck   [_~~_]        */
-               sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
-               data = (data << 1) | ((de620_get_register(dev, R_STS) & EEDI) >> 7);
-       }
-       /* cs    [____] RESET SEND STATE */
-       /* di    [____]                  */
-       /* sck   [_~~_]                  */
-       sendit(dev, 0); sendit(dev, 1); sendit(dev, 1); sendit(dev, 0);
-
-       return data;
-}
-
-static int __init read_eeprom(struct net_device *dev)
-{
-       unsigned short wrd;
-
-       /* D-Link Ethernet addresses are in the series  00:80:c8:7X:XX:XX:XX */
-       wrd = ReadAWord(dev, 0x1aa);    /* bytes 0 + 1 of NodeID */
-       if (!clone && (wrd != htons(0x0080))) /* Valid D-Link ether sequence? */
-               return -1; /* Nope, not a DE-620 */
-       nic_data.NodeID[0] = wrd & 0xff;
-       nic_data.NodeID[1] = wrd >> 8;
-
-       wrd = ReadAWord(dev, 0x1ab);    /* bytes 2 + 3 of NodeID */
-       if (!clone && ((wrd & 0xff) != 0xc8)) /* Valid D-Link ether sequence? */
-               return -1; /* Nope, not a DE-620 */
-       nic_data.NodeID[2] = wrd & 0xff;
-       nic_data.NodeID[3] = wrd >> 8;
-
-       wrd = ReadAWord(dev, 0x1ac);    /* bytes 4 + 5 of NodeID */
-       nic_data.NodeID[4] = wrd & 0xff;
-       nic_data.NodeID[5] = wrd >> 8;
-
-       wrd = ReadAWord(dev, 0x1ad);    /* RAM size in pages (256 bytes). 0 = 64k */
-       nic_data.RAM_Size = (wrd >> 8);
-
-       wrd = ReadAWord(dev, 0x1ae);    /* hardware model (CT = 3) */
-       nic_data.Model = (wrd & 0xff);
-
-       wrd = ReadAWord(dev, 0x1af); /* media (indicates BNC/UTP) */
-       nic_data.Media = (wrd & 0xff);
-
-       wrd = ReadAWord(dev, 0x1a8); /* System Configuration Register */
-       nic_data.SCR = (wrd >> 8);
-
-       return 0; /* no errors */
-}
-
-/******************************************************************************
- *
- * Loadable module skeleton
- *
- */
-#ifdef MODULE
-static struct net_device *de620_dev;
-
-int __init init_module(void)
-{
-       de620_dev = de620_probe(-1);
-       if (IS_ERR(de620_dev))
-               return PTR_ERR(de620_dev);
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       unregister_netdev(de620_dev);
-       release_region(de620_dev->base_addr, 3);
-       free_netdev(de620_dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de620.h b/drivers/net/ethernet/dlink/de620.h
deleted file mode 100644 (file)
index e8d9a88..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*********************************************************
- *                                                       *
- * Definition of D-Link DE-620 Ethernet Pocket adapter   *
- *                                                       *
- *********************************************************/
-
-/* DE-620's CMD port Command */
-#define CS0            0x08    /* 1->0 command strobe */
-#define ICEN           0x04    /* 0=enable DL3520 host interface */
-#define DS0            0x02    /* 1->0 data strobe 0 */
-#define DS1            0x01    /* 1->0 data strobe 1 */
-
-#define WDIR           0x20    /* general 0=read  1=write */
-#define RDIR           0x00    /*  (not 100% confirm ) */
-#define PS2WDIR                0x00    /* ps/2 mode 1=read, 0=write */
-#define PS2RDIR                0x20
-
-#define IRQEN          0x10    /* 1 = enable printer IRQ line */
-#define SELECTIN       0x08    /* 1 = select printer */
-#define INITP          0x04    /* 0 = initial printer */
-#define AUTOFEED       0x02    /* 1 = printer auto form feed */
-#define STROBE         0x01    /* 0->1 data strobe */
-
-#define RESET          0x08
-#define NIS0           0x20    /* 0 = BNC, 1 = UTP */
-#define NCTL0          0x10
-
-/* DE-620 DIC Command */
-#define W_DUMMY                0x00    /* DIC reserved command */
-#define W_CR           0x20    /* DIC write command register */
-#define W_NPR          0x40    /* DIC write Next Page Register */
-#define W_TBR          0x60    /* DIC write Tx Byte Count 1 reg */
-#define W_RSA          0x80    /* DIC write Remote Start Addr 1 */
-
-/* DE-620's STAT port bits 7-4 */
-#define EMPTY          0x80    /* 1 = receive buffer empty */
-#define INTLEVEL       0x40    /* 1 = interrupt level is high */
-#define TXBF1          0x20    /* 1 = transmit buffer 1 is in use */
-#define TXBF0          0x10    /* 1 = transmit buffer 0 is in use */
-#define READY          0x08    /* 1 = h/w ready to accept cmd/data */
-
-/* IDC 1 Command */
-#define        W_RSA1          0xa0    /* write remote start address 1 */
-#define        W_RSA0          0xa1    /* write remote start address 0 */
-#define        W_NPRF          0xa2    /* write next page register NPR15-NPR8 */
-#define        W_DFR           0xa3    /* write delay factor register */
-#define        W_CPR           0xa4    /* write current page register */
-#define        W_SPR           0xa5    /* write start page register */
-#define        W_EPR           0xa6    /* write end page register */
-#define        W_SCR           0xa7    /* write system configuration register */
-#define        W_TCR           0xa8    /* write Transceiver Configuration reg */
-#define        W_EIP           0xa9    /* write EEPM Interface port */
-#define        W_PAR0          0xaa    /* write physical address register 0 */
-#define        W_PAR1          0xab    /* write physical address register 1 */
-#define        W_PAR2          0xac    /* write physical address register 2 */
-#define        W_PAR3          0xad    /* write physical address register 3 */
-#define        W_PAR4          0xae    /* write physical address register 4 */
-#define        W_PAR5          0xaf    /* write physical address register 5 */
-
-/* IDC 2 Command */
-#define        R_STS           0xc0    /* read status register */
-#define        R_CPR           0xc1    /* read current page register */
-#define        R_BPR           0xc2    /* read boundary page register */
-#define        R_TDR           0xc3    /* read time domain reflectometry reg */
-
-/* STATUS Register */
-#define EEDI           0x80    /* EEPM DO pin */
-#define TXSUC          0x40    /* tx success */
-#define T16            0x20    /* tx fail 16 times */
-#define TS1            0x40    /* 0=Tx success, 1=T16 */
-#define TS0            0x20    /* 0=Tx success, 1=T16 */
-#define RXGOOD         0x10    /* rx a good packet */
-#define RXCRC          0x08    /* rx a CRC error packet */
-#define RXSHORT                0x04    /* rx a short packet */
-#define COLS           0x02    /* coaxial collision status */
-#define LNKS           0x01    /* UTP link status */
-
-/* Command Register */
-#define CLEAR          0x10    /* reset part of hardware */
-#define NOPER          0x08    /* No Operation */
-#define RNOP           0x08
-#define RRA            0x06    /* After RR then auto-advance NPR & BPR(=NPR-1) */
-#define RRN            0x04    /* Normal Remote Read mode */
-#define RW1            0x02    /* Remote Write tx buffer 1  ( page 6 - 11 ) */
-#define RW0            0x00    /* Remote Write tx buffer 0  ( page 0 - 5 ) */
-#define TXEN           0x01    /* 0->1 tx enable */
-
-/* System Configuration Register */
-#define TESTON         0x80    /* test host data transfer reliability */
-#define SLEEP          0x40    /* sleep mode */
-#if 0
-#define FASTMODE       0x04    /* fast mode for intel 82360SL fast mode */
-#define BYTEMODE       0x02    /* byte mode */
-#else
-#define FASTMODE       0x20    /* fast mode for intel 82360SL fast mode */
-#define BYTEMODE       0x10    /* byte mode */
-#endif
-#define NIBBLEMODE     0x00    /* nibble mode */
-#define IRQINV         0x08    /* turn off IRQ line inverter */
-#define IRQNML         0x00    /* turn on IRQ line inverter */
-#define INTON          0x04
-#define AUTOFFSET      0x02    /* auto shift address to TPR+12 */
-#define AUTOTX         0x01    /* auto tx when leave RW mode */
-
-/* Transceiver Configuration Register */
-#define JABBER         0x80    /* generate jabber condition */
-#define TXSUCINT       0x40    /* enable tx success interrupt */
-#define T16INT         0x20    /* enable T16 interrupt */
-#define RXERRPKT       0x10    /* accept CRC error or short packet */
-#define EXTERNALB2     0x0C    /* external loopback 2 */
-#define EXTERNALB1     0x08    /* external loopback 1 */
-#define INTERNALB      0x04    /* internal loopback */
-#define NMLOPERATE     0x00    /* normal operation */
-#define RXPBM          0x03    /* rx physical, broadcast, multicast */
-#define RXPB           0x02    /* rx physical, broadcast */
-#define RXALL          0x01    /* rx all packet */
-#define RXOFF          0x00    /* rx disable */
index 1d342d37915cd1d45b8c00088079e6aef2b273fc..110d26f4c6028f37d773576d4dd3a5a2d13fd5b3 100644 (file)
@@ -1156,9 +1156,10 @@ set_multicast (struct net_device *dev)
 static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct netdev_private *np = netdev_priv(dev);
-       strcpy(info->driver, "dl2k");
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pdev));
+
+       strlcpy(info->driver, "dl2k", sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
 }
 
 static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 28fc11b2f1ea9235ce8c9fdb3ac8abbb35b72bac..50d9c631593090e8d2b335fcb4d947346091fa42 100644 (file)
@@ -530,7 +530,6 @@ static int sundance_probe1(struct pci_dev *pdev,
        for (i = 0; i < 3; i++)
                ((__le16 *)dev->dev_addr)[i] =
                        cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        np = netdev_priv(dev);
        np->base = ioaddr;
index 2c177b329c8bd4ccd1bad6ffef72deab6b3dc8a1..f3d60eb13c3aea0b1e1141294655b398a19ba159 100644 (file)
@@ -281,11 +281,11 @@ static int dnet_mii_probe(struct net_device *dev)
        /* attach the mac to the phy */
        if (bp->capabilities & DNET_HAS_RMII) {
                phydev = phy_connect(dev, dev_name(&phydev->dev),
-                                    &dnet_handle_link_change, 0,
+                                    &dnet_handle_link_change,
                                     PHY_INTERFACE_MODE_RMII);
        } else {
                phydev = phy_connect(dev, dev_name(&phydev->dev),
-                                    &dnet_handle_link_change, 0,
+                                    &dnet_handle_link_change,
                                     PHY_INTERFACE_MODE_MII);
        }
 
index 00454a10f88d6111f5bfb30987703c04d807e8ba..76b302f30c8727fe638a8e9783f8246c037f1db6 100644 (file)
@@ -183,12 +183,12 @@ static void be_get_drvinfo(struct net_device *netdev,
 
        strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
        strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version));
-       strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
-       if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) {
-               strcat(drvinfo->fw_version, " [");
-               strcat(drvinfo->fw_version, fw_on_flash);
-               strcat(drvinfo->fw_version, "]");
-       }
+       if (!memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN))
+               strlcpy(drvinfo->fw_version, adapter->fw_ver,
+                       sizeof(drvinfo->fw_version));
+       else
+               snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+                        "%s [%s]", adapter->fw_ver, fw_on_flash);
 
        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
                sizeof(drvinfo->bus_info));
index 8db1c06008de16107ba5475580a696f04a5d745a..5722bc61fa582d0796a4ce37b2e8912c4840cc59 100644 (file)
@@ -206,7 +206,7 @@ struct ethoc {
        unsigned int num_rx;
        unsigned int cur_rx;
 
-       void** vma;
+       void **vma;
 
        struct net_device *netdev;
        struct napi_struct napi;
@@ -292,7 +292,7 @@ static int ethoc_init_ring(struct ethoc *dev, unsigned long mem_start)
 {
        struct ethoc_bd bd;
        int i;
-       voidvma;
+       void *vma;
 
        dev->cur_tx = 0;
        dev->dty_tx = 0;
@@ -447,8 +447,8 @@ static int ethoc_rx(struct net_device *dev, int limit)
                                netif_receive_skb(skb);
                        } else {
                                if (net_ratelimit())
-                                       dev_warn(&dev->dev, "low on memory - "
-                                                       "packet dropped\n");
+                                       dev_warn(&dev->dev,
+                                           "low on memory - packet dropped\n");
 
                                dev->stats.rx_dropped++;
                                break;
@@ -555,9 +555,8 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
        pending = ethoc_read(priv, INT_SOURCE);
        pending &= mask;
 
-       if (unlikely(pending == 0)) {
+       if (unlikely(pending == 0))
                return IRQ_NONE;
-       }
 
        ethoc_ack_irq(priv, pending);
 
@@ -620,7 +619,7 @@ static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
        ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
        ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ);
 
-       for (i=0; i < 5; i++) {
+       for (i = 0; i < 5; i++) {
                u32 status = ethoc_read(priv, MIISTATUS);
                if (!(status & MIISTATUS_BUSY)) {
                        u32 data = ethoc_read(priv, MIIRX_DATA);
@@ -628,7 +627,7 @@ static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
                        ethoc_write(priv, MIICOMMAND, 0);
                        return data;
                }
-               usleep_range(100,200);
+               usleep_range(100, 200);
        }
 
        return -EBUSY;
@@ -643,14 +642,14 @@ static int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
        ethoc_write(priv, MIITX_DATA, val);
        ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE);
 
-       for (i=0; i < 5; i++) {
+       for (i = 0; i < 5; i++) {
                u32 stat = ethoc_read(priv, MIISTATUS);
                if (!(stat & MIISTATUS_BUSY)) {
                        /* reset MII command register */
                        ethoc_write(priv, MIICOMMAND, 0);
                        return 0;
                }
-               usleep_range(100,200);
+               usleep_range(100, 200);
        }
 
        return -EBUSY;
@@ -671,19 +670,18 @@ static int ethoc_mdio_probe(struct net_device *dev)
        struct phy_device *phy;
        int err;
 
-       if (priv->phy_id != -1) {
+       if (priv->phy_id != -1)
                phy = priv->mdio->phy_map[priv->phy_id];
-       } else {
+       else
                phy = phy_find_first(priv->mdio);
-       }
 
        if (!phy) {
                dev_err(&dev->dev, "no PHY found\n");
                return -ENXIO;
        }
 
-       err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0,
-                       PHY_INTERFACE_MODE_GMII);
+       err = phy_connect_direct(dev, phy, ethoc_mdio_poll,
+                                PHY_INTERFACE_MODE_GMII);
        if (err) {
                dev_err(&dev->dev, "could not attach to PHY\n");
                return err;
@@ -771,21 +769,24 @@ static int ethoc_config(struct net_device *dev, struct ifmap *map)
        return -ENOSYS;
 }
 
-static int ethoc_set_mac_address(struct net_device *dev, void *addr)
+static void ethoc_do_set_mac_address(struct net_device *dev)
 {
        struct ethoc *priv = netdev_priv(dev);
-       u8 *mac = (u8 *)addr;
-
-       if (!is_valid_ether_addr(mac))
-               return -EADDRNOTAVAIL;
+       unsigned char *mac = dev->dev_addr;
 
        ethoc_write(priv, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
                                     (mac[4] <<  8) | (mac[5] <<  0));
        ethoc_write(priv, MAC_ADDR1, (mac[0] <<  8) | (mac[1] <<  0));
+}
 
-       memcpy(dev->dev_addr, mac, ETH_ALEN);
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
+static int ethoc_set_mac_address(struct net_device *dev, void *p)
+{
+       const struct sockaddr *addr = p;
 
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       ethoc_do_set_mac_address(dev);
        return 0;
 }
 
@@ -1022,7 +1023,7 @@ static int ethoc_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n",
                priv->num_tx, priv->num_rx);
 
-       priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL);
+       priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void *), GFP_KERNEL);
        if (!priv->vma) {
                ret = -ENOMEM;
                goto error;
@@ -1038,7 +1039,7 @@ static int ethoc_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_OF
                {
-               const uint8_tmac;
+               const uint8_t *mac;
 
                mac = of_get_property(pdev->dev.of_node,
                                      "local-mac-address",
@@ -1050,25 +1051,23 @@ static int ethoc_probe(struct platform_device *pdev)
        }
 
        /* Check that the given MAC address is valid. If it isn't, read the
-        * current MAC from the controller. */
+        * current MAC from the controller.
+        */
        if (!is_valid_ether_addr(netdev->dev_addr))
                ethoc_get_mac_address(netdev, netdev->dev_addr);
 
        /* Check the MAC again for validity, if it still isn't choose and
-        * program a random one. */
+        * program a random one.
+        */
        if (!is_valid_ether_addr(netdev->dev_addr)) {
                eth_random_addr(netdev->dev_addr);
                random_mac = true;
        }
 
-       ret = ethoc_set_mac_address(netdev, netdev->dev_addr);
-       if (ret) {
-               dev_err(&netdev->dev, "failed to set MAC address\n");
-               goto error;
-       }
+       ethoc_do_set_mac_address(netdev);
 
        if (random_mac)
-               netdev->addr_assign_type |= NET_ADDR_RANDOM;
+               netdev->addr_assign_type = NET_ADDR_RANDOM;
 
        /* register MII bus */
        priv->mdio = mdiobus_alloc();
index 74d749e29aab7725888ec8a273b5ecdd4522dc06..7c361d1db94cbccdb937368044b30913d891ba7f 100644 (file)
@@ -858,8 +858,7 @@ static int ftgmac100_mii_probe(struct ftgmac100 *priv)
        }
 
        phydev = phy_connect(netdev, dev_name(&phydev->dev),
-                            &ftgmac100_adjust_link, 0,
-                            PHY_INTERFACE_MODE_GMII);
+                            &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII);
 
        if (IS_ERR(phydev)) {
                netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
@@ -955,9 +954,9 @@ static int ftgmac100_mdiobus_reset(struct mii_bus *bus)
 static void ftgmac100_get_drvinfo(struct net_device *netdev,
                                  struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, dev_name(&netdev->dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
 }
 
 static int ftgmac100_get_settings(struct net_device *netdev,
index b901a01e3fa5073f4b5c8039d94cf04c7beaa849..b5ea8fbd8a76d19597714b8e35772e9037647a86 100644 (file)
@@ -820,9 +820,9 @@ static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
 static void ftmac100_get_drvinfo(struct net_device *netdev,
                                 struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, dev_name(&netdev->dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
 }
 
 static int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
index ec490d741fc00dbd895de8869340af41fe0b15ce..6048dc8604ee6139235f45f2736d9cd5b385dfa0 100644 (file)
@@ -26,6 +26,7 @@ config FEC
                   ARCH_MXC || SOC_IMX28)
        default ARCH_MXC || SOC_IMX28 if ARM
        select PHYLIB
+       select PTP_1588_CLOCK
        ---help---
          Say Y here if you want to use the built-in 10/100 Fast ethernet
          controller on some Motorola ColdFire and Freescale i.MX processors.
@@ -92,12 +93,4 @@ config GIANFAR
          This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
          and MPC86xx family of chips, and the FEC on the 8540.
 
-config FEC_PTP
-       bool "PTP Hardware Clock (PHC)"
-       depends on FEC && ARCH_MXC && !SOC_IMX25 && !SOC_IMX27 && !SOC_IMX35 && !SOC_IMX5
-       select PTP_1588_CLOCK
-       --help---
-         Say Y here if you want to use PTP Hardware Clock (PHC) in the
-         driver.  Only the basic clock operations have been implemented.
-
 endif # NET_VENDOR_FREESCALE
index d4d19b3d00aed69b8d905307f16b53e717926dcc..b7d58fe6f531635acebc3d4d7c00e80fc63414e7 100644 (file)
@@ -2,8 +2,7 @@
 # Makefile for the Freescale network device drivers.
 #
 
-obj-$(CONFIG_FEC) += fec.o
-obj-$(CONFIG_FEC_PTP) += fec_ptp.o
+obj-$(CONFIG_FEC) += fec.o fec_ptp.o
 obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
 ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
        obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
index 0704bcab178ab64a036e6cec7e44167622c7271c..0287675ddffb9f5feeaa5cc937fa9c41328989b9 100644 (file)
 #endif
 
 #define DRIVER_NAME    "fec"
+#define FEC_NAPI_WEIGHT        64
+
+/* Pause frame feild and FIFO threshold */
+#define FEC_ENET_FCE   (1 << 5)
+#define FEC_ENET_RSEM_V        0x84
+#define FEC_ENET_RSFL_V        16
+#define FEC_ENET_RAEM_V        0x8
+#define FEC_ENET_RAFL_V        0x8
+#define FEC_ENET_OPD_V 0xFFF0
 
 /* Controller is ENET-MAC */
 #define FEC_QUIRK_ENET_MAC             (1 << 0)
@@ -76,6 +85,8 @@
 #define FEC_QUIRK_USE_GASKET           (1 << 2)
 /* Controller has GBIT support */
 #define FEC_QUIRK_HAS_GBIT             (1 << 3)
+/* Controller has extend desc buffer */
+#define FEC_QUIRK_HAS_BUFDESC_EX       (1 << 4)
 
 static struct platform_device_id fec_devtype[] = {
        {
@@ -93,7 +104,8 @@ static struct platform_device_id fec_devtype[] = {
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
        }, {
                .name = "imx6q-fec",
-               .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT,
+               .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+                               FEC_QUIRK_HAS_BUFDESC_EX,
        }, {
                /* sentinel */
        }
@@ -140,7 +152,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #endif
 #endif /* CONFIG_M5272 */
 
-#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
+#if (((RX_RING_SIZE + TX_RING_SIZE) * 32) > PAGE_SIZE)
 #error "FEC: descriptor ring size constants too large"
 #endif
 
@@ -157,6 +169,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #define FEC_ENET_EBERR ((uint)0x00400000)      /* SDMA bus error */
 
 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
 
 /* The FEC stores dest/src/type, data, and checksum for receive packets.
  */
@@ -190,8 +203,29 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
+#define FEC_PAUSE_FLAG_AUTONEG 0x1
+#define FEC_PAUSE_FLAG_ENABLE  0x2
+
 static int mii_cnt;
 
+static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, int is_ex)
+{
+       struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp;
+       if (is_ex)
+               return (struct bufdesc *)(ex + 1);
+       else
+               return bdp + 1;
+}
+
+static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, int is_ex)
+{
+       struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp;
+       if (is_ex)
+               return (struct bufdesc *)(ex - 1);
+       else
+               return bdp - 1;
+}
+
 static void *swap_buffer(void *bufaddr, int len)
 {
        int i;
@@ -248,7 +282,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
         */
        if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
                unsigned int index;
-               index = bdp - fep->tx_bd_base;
+               if (fep->bufdesc_ex)
+                       index = (struct bufdesc_ex *)bdp -
+                               (struct bufdesc_ex *)fep->tx_bd_base;
+               else
+                       index = bdp - fep->tx_bd_base;
                memcpy(fep->tx_bounce[index], skb->data, skb->len);
                bufaddr = fep->tx_bounce[index];
        }
@@ -280,17 +318,19 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        | BD_ENET_TX_LAST | BD_ENET_TX_TC);
        bdp->cbd_sc = status;
 
-#ifdef CONFIG_FEC_PTP
-       bdp->cbd_bdu = 0;
-       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+       if (fep->bufdesc_ex) {
+
+               struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+               ebdp->cbd_bdu = 0;
+               if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
                        fep->hwts_tx_en)) {
-                       bdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
+                       ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
                        skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-       } else {
+               } else {
 
-               bdp->cbd_esc = BD_ENET_TX_INT;
+                       ebdp->cbd_esc = BD_ENET_TX_INT;
+               }
        }
-#endif
        /* Trigger transmission start */
        writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
@@ -298,7 +338,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        if (status & BD_ENET_TX_WRAP)
                bdp = fep->tx_bd_base;
        else
-               bdp++;
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 
        if (bdp == fep->dirty_tx) {
                fep->tx_full = 1;
@@ -359,8 +399,12 @@ fec_restart(struct net_device *ndev, int duplex)
 
        /* Set receive and transmit descriptor base. */
        writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
-       writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE,
-                       fep->hwp + FEC_X_DES_START);
+       if (fep->bufdesc_ex)
+               writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
+                       * RX_RING_SIZE, fep->hwp + FEC_X_DES_START);
+       else
+               writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
+                       * RX_RING_SIZE, fep->hwp + FEC_X_DES_START);
 
        fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
        fep->cur_rx = fep->rx_bd_base;
@@ -439,6 +483,25 @@ fec_restart(struct net_device *ndev, int duplex)
                }
 #endif
        }
+
+       /* enable pause frame*/
+       if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
+           ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
+            fep->phy_dev && fep->phy_dev->pause)) {
+               rcntl |= FEC_ENET_FCE;
+
+               /* set FIFO thresh hold parameter to reduce overrun */
+               writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
+               writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
+               writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
+               writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
+
+               /* OPD */
+               writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
+       } else {
+               rcntl &= ~FEC_ENET_FCE;
+       }
+
        writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
        if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
@@ -448,17 +511,16 @@ fec_restart(struct net_device *ndev, int duplex)
                writel(1 << 8, fep->hwp + FEC_X_WMRK);
        }
 
-#ifdef CONFIG_FEC_PTP
-       ecntl |= (1 << 4);
-#endif
+       if (fep->bufdesc_ex)
+               ecntl |= (1 << 4);
 
        /* And last, enable the transmit and receive processing */
        writel(ecntl, fep->hwp + FEC_ECNTRL);
        writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
-#ifdef CONFIG_FEC_PTP
-       fec_ptp_start_cyclecounter(ndev);
-#endif
+       if (fep->bufdesc_ex)
+               fec_ptp_start_cyclecounter(ndev);
+
        /* Enable interrupts we wish to service */
        writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 }
@@ -544,19 +606,20 @@ fec_enet_tx(struct net_device *ndev)
                        ndev->stats.tx_packets++;
                }
 
-#ifdef CONFIG_FEC_PTP
-               if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+               if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
+                       fep->bufdesc_ex) {
                        struct skb_shared_hwtstamps shhwtstamps;
                        unsigned long flags;
+                       struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
 
                        memset(&shhwtstamps, 0, sizeof(shhwtstamps));
                        spin_lock_irqsave(&fep->tmreg_lock, flags);
                        shhwtstamps.hwtstamp = ns_to_ktime(
-                               timecounter_cyc2time(&fep->tc, bdp->ts));
+                               timecounter_cyc2time(&fep->tc, ebdp->ts));
                        spin_unlock_irqrestore(&fep->tmreg_lock, flags);
                        skb_tstamp_tx(skb, &shhwtstamps);
                }
-#endif
+
                if (status & BD_ENET_TX_READY)
                        printk("HEY! Enet xmit interrupt and TX_READY.\n");
 
@@ -575,7 +638,7 @@ fec_enet_tx(struct net_device *ndev)
                if (status & BD_ENET_TX_WRAP)
                        bdp = fep->tx_bd_base;
                else
-                       bdp++;
+                       bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 
                /* Since we have freed up a buffer, the ring is no longer full
                 */
@@ -595,8 +658,8 @@ fec_enet_tx(struct net_device *ndev)
  * not been given to the system, we just set the empty indicator,
  * effectively tossing the packet.
  */
-static void
-fec_enet_rx(struct net_device *ndev)
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
        const struct platform_device_id *id_entry =
@@ -606,13 +669,12 @@ fec_enet_rx(struct net_device *ndev)
        struct  sk_buff *skb;
        ushort  pkt_len;
        __u8 *data;
+       int     pkt_received = 0;
 
 #ifdef CONFIG_M532x
        flush_cache_all();
 #endif
 
-       spin_lock(&fep->hw_lock);
-
        /* First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
         */
@@ -620,6 +682,10 @@ fec_enet_rx(struct net_device *ndev)
 
        while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
+               if (pkt_received >= budget)
+                       break;
+               pkt_received++;
+
                /* Since we have allocated space to hold a complete frame,
                 * the last indicator should be set.
                 */
@@ -683,23 +749,25 @@ fec_enet_rx(struct net_device *ndev)
                        skb_put(skb, pkt_len - 4);      /* Make room */
                        skb_copy_to_linear_data(skb, data, pkt_len - 4);
                        skb->protocol = eth_type_trans(skb, ndev);
-#ifdef CONFIG_FEC_PTP
+
                        /* Get receive timestamp from the skb */
-                       if (fep->hwts_rx_en) {
+                       if (fep->hwts_rx_en && fep->bufdesc_ex) {
                                struct skb_shared_hwtstamps *shhwtstamps =
                                                            skb_hwtstamps(skb);
                                unsigned long flags;
+                               struct bufdesc_ex *ebdp =
+                                       (struct bufdesc_ex *)bdp;
 
                                memset(shhwtstamps, 0, sizeof(*shhwtstamps));
 
                                spin_lock_irqsave(&fep->tmreg_lock, flags);
                                shhwtstamps->hwtstamp = ns_to_ktime(
-                                   timecounter_cyc2time(&fep->tc, bdp->ts));
+                                   timecounter_cyc2time(&fep->tc, ebdp->ts));
                                spin_unlock_irqrestore(&fep->tmreg_lock, flags);
                        }
-#endif
+
                        if (!skb_defer_rx_timestamp(skb))
-                               netif_rx(skb);
+                               napi_gro_receive(&fep->napi, skb);
                }
 
                bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
@@ -712,17 +780,19 @@ rx_processing_done:
                status |= BD_ENET_RX_EMPTY;
                bdp->cbd_sc = status;
 
-#ifdef CONFIG_FEC_PTP
-               bdp->cbd_esc = BD_ENET_RX_INT;
-               bdp->cbd_prot = 0;
-               bdp->cbd_bdu = 0;
-#endif
+               if (fep->bufdesc_ex) {
+                       struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+
+                       ebdp->cbd_esc = BD_ENET_RX_INT;
+                       ebdp->cbd_prot = 0;
+                       ebdp->cbd_bdu = 0;
+               }
 
                /* Update BD pointer to next entry */
                if (status & BD_ENET_RX_WRAP)
                        bdp = fep->rx_bd_base;
                else
-                       bdp++;
+                       bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
                /* Doing this here will keep the FEC running while we process
                 * incoming frames.  On a heavily loaded network, we should be
                 * able to keep up at the expense of system resources.
@@ -731,7 +801,7 @@ rx_processing_done:
        }
        fep->cur_rx = bdp;
 
-       spin_unlock(&fep->hw_lock);
+       return pkt_received;
 }
 
 static irqreturn_t
@@ -748,7 +818,13 @@ fec_enet_interrupt(int irq, void *dev_id)
 
                if (int_events & FEC_ENET_RXF) {
                        ret = IRQ_HANDLED;
-                       fec_enet_rx(ndev);
+
+                       /* Disable the RX interrupt */
+                       if (napi_schedule_prep(&fep->napi)) {
+                               writel(FEC_RX_DISABLED_IMASK,
+                                       fep->hwp + FEC_IMASK);
+                               __napi_schedule(&fep->napi);
+                       }
                }
 
                /* Transmit OK, or non-fatal error. Update the buffer
@@ -769,10 +845,21 @@ fec_enet_interrupt(int irq, void *dev_id)
        return ret;
 }
 
+static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
+{
+       struct net_device *ndev = napi->dev;
+       int pkts = fec_enet_rx(ndev, budget);
+       struct fec_enet_private *fep = netdev_priv(ndev);
 
+       if (pkts < budget) {
+               napi_complete(napi);
+               writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+       }
+       return pkts;
+}
 
 /* ------------------------------------------------------------------------- */
-static void __inline__ fec_get_mac(struct net_device *ndev)
+static void fec_get_mac(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
        struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
@@ -973,7 +1060,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
        }
 
        snprintf(phy_name, sizeof(phy_name), PHY_ID_FMT, mdio_bus_id, phy_id);
-       phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
+       phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,
                              fep->phy_interface);
        if (IS_ERR(phy_dev)) {
                printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
@@ -981,8 +1068,10 @@ static int fec_enet_mii_probe(struct net_device *ndev)
        }
 
        /* mask with MAC supported features */
-       if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
+       if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
                phy_dev->supported &= PHY_GBIT_FEATURES;
+               phy_dev->supported |= SUPPORTED_Pause;
+       }
        else
                phy_dev->supported &= PHY_BASIC_FEATURES;
 
@@ -1133,17 +1222,95 @@ static void fec_enet_get_drvinfo(struct net_device *ndev,
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
 
-       strcpy(info->driver, fep->pdev->dev.driver->name);
-       strcpy(info->version, "Revision: 1.0");
-       strcpy(info->bus_info, dev_name(&ndev->dev));
+       strlcpy(info->driver, fep->pdev->dev.driver->name,
+               sizeof(info->driver));
+       strlcpy(info->version, "Revision: 1.0", sizeof(info->version));
+       strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info));
+}
+
+static int fec_enet_get_ts_info(struct net_device *ndev,
+                               struct ethtool_ts_info *info)
+{
+       struct fec_enet_private *fep = netdev_priv(ndev);
+
+       if (fep->bufdesc_ex) {
+
+               info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+                                       SOF_TIMESTAMPING_RX_SOFTWARE |
+                                       SOF_TIMESTAMPING_SOFTWARE |
+                                       SOF_TIMESTAMPING_TX_HARDWARE |
+                                       SOF_TIMESTAMPING_RX_HARDWARE |
+                                       SOF_TIMESTAMPING_RAW_HARDWARE;
+               if (fep->ptp_clock)
+                       info->phc_index = ptp_clock_index(fep->ptp_clock);
+               else
+                       info->phc_index = -1;
+
+               info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+                                (1 << HWTSTAMP_TX_ON);
+
+               info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+                                  (1 << HWTSTAMP_FILTER_ALL);
+               return 0;
+       } else {
+               return ethtool_op_get_ts_info(ndev, info);
+       }
+}
+
+static void fec_enet_get_pauseparam(struct net_device *ndev,
+                                   struct ethtool_pauseparam *pause)
+{
+       struct fec_enet_private *fep = netdev_priv(ndev);
+
+       pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0;
+       pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0;
+       pause->rx_pause = pause->tx_pause;
+}
+
+static int fec_enet_set_pauseparam(struct net_device *ndev,
+                                  struct ethtool_pauseparam *pause)
+{
+       struct fec_enet_private *fep = netdev_priv(ndev);
+
+       if (pause->tx_pause != pause->rx_pause) {
+               netdev_info(ndev,
+                       "hardware only support enable/disable both tx and rx");
+               return -EINVAL;
+       }
+
+       fep->pause_flag = 0;
+
+       /* tx pause must be same as rx pause */
+       fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
+       fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
+
+       if (pause->rx_pause || pause->autoneg) {
+               fep->phy_dev->supported |= ADVERTISED_Pause;
+               fep->phy_dev->advertising |= ADVERTISED_Pause;
+       } else {
+               fep->phy_dev->supported &= ~ADVERTISED_Pause;
+               fep->phy_dev->advertising &= ~ADVERTISED_Pause;
+       }
+
+       if (pause->autoneg) {
+               if (netif_running(ndev))
+                       fec_stop(ndev);
+               phy_start_aneg(fep->phy_dev);
+       }
+       if (netif_running(ndev))
+               fec_restart(ndev, 0);
+
+       return 0;
 }
 
 static const struct ethtool_ops fec_enet_ethtool_ops = {
+       .get_pauseparam         = fec_enet_get_pauseparam,
+       .set_pauseparam         = fec_enet_set_pauseparam,
        .get_settings           = fec_enet_get_settings,
        .set_settings           = fec_enet_set_settings,
        .get_drvinfo            = fec_enet_get_drvinfo,
        .get_link               = ethtool_op_get_link,
-       .get_ts_info            = ethtool_op_get_ts_info,
+       .get_ts_info            = fec_enet_get_ts_info,
 };
 
 static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -1157,10 +1324,9 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
        if (!phydev)
                return -ENODEV;
 
-#ifdef CONFIG_FEC_PTP
-       if (cmd == SIOCSHWTSTAMP)
+       if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex)
                return fec_ptp_ioctl(ndev, rq, cmd);
-#endif
+
        return phy_mii_ioctl(phydev, rq, cmd);
 }
 
@@ -1180,7 +1346,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
                                        FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
                if (skb)
                        dev_kfree_skb(skb);
-               bdp++;
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
        }
 
        bdp = fep->tx_bd_base;
@@ -1207,14 +1373,17 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
                bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
                                FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
                bdp->cbd_sc = BD_ENET_RX_EMPTY;
-#ifdef CONFIG_FEC_PTP
-               bdp->cbd_esc = BD_ENET_RX_INT;
-#endif
-               bdp++;
+
+               if (fep->bufdesc_ex) {
+                       struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+                       ebdp->cbd_esc = BD_ENET_RX_INT;
+               }
+
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
        }
 
        /* Set the last buffer to wrap. */
-       bdp--;
+       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
        bdp->cbd_sc |= BD_SC_WRAP;
 
        bdp = fep->tx_bd_base;
@@ -1224,14 +1393,16 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
                bdp->cbd_sc = 0;
                bdp->cbd_bufaddr = 0;
 
-#ifdef CONFIG_FEC_PTP
-               bdp->cbd_esc = BD_ENET_RX_INT;
-#endif
-               bdp++;
+               if (fep->bufdesc_ex) {
+                       struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+                       ebdp->cbd_esc = BD_ENET_RX_INT;
+               }
+
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
        }
 
        /* Set the last buffer to wrap. */
-       bdp--;
+       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
        bdp->cbd_sc |= BD_SC_WRAP;
 
        return 0;
@@ -1243,6 +1414,8 @@ fec_enet_open(struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        int ret;
 
+       napi_enable(&fep->napi);
+
        /* I should reset the ring buffers here, but I don't yet know
         * a simple way to do that.
         */
@@ -1444,24 +1617,31 @@ static int fec_enet_init(struct net_device *ndev)
 
        /* Set receive and transmit descriptor base. */
        fep->rx_bd_base = cbd_base;
-       fep->tx_bd_base = cbd_base + RX_RING_SIZE;
+       if (fep->bufdesc_ex)
+               fep->tx_bd_base = (struct bufdesc *)
+                       (((struct bufdesc_ex *)cbd_base) + RX_RING_SIZE);
+       else
+               fep->tx_bd_base = cbd_base + RX_RING_SIZE;
 
        /* The FEC Ethernet specific entries in the device structure */
        ndev->watchdog_timeo = TX_TIMEOUT;
        ndev->netdev_ops = &fec_netdev_ops;
        ndev->ethtool_ops = &fec_enet_ethtool_ops;
 
+       writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
+       netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
+
        /* Initialize the receive buffer descriptors. */
        bdp = fep->rx_bd_base;
        for (i = 0; i < RX_RING_SIZE; i++) {
 
                /* Initialize the BD for every fragment in the page. */
                bdp->cbd_sc = 0;
-               bdp++;
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
        }
 
        /* Set the last buffer to wrap */
-       bdp--;
+       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
        bdp->cbd_sc |= BD_SC_WRAP;
 
        /* ...and the same for transmit */
@@ -1471,11 +1651,11 @@ static int fec_enet_init(struct net_device *ndev)
                /* Initialize the BD for every fragment in the page. */
                bdp->cbd_sc = 0;
                bdp->cbd_bufaddr = 0;
-               bdp++;
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
        }
 
        /* Set the last buffer to wrap */
-       bdp--;
+       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
        bdp->cbd_sc |= BD_SC_WRAP;
 
        fec_restart(ndev, 0);
@@ -1519,12 +1699,12 @@ static void fec_reset_phy(struct platform_device *pdev)
        gpio_set_value(phy_reset, 1);
 }
 #else /* CONFIG_OF */
-static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
+static int fec_get_phy_mode_dt(struct platform_device *pdev)
 {
        return -ENODEV;
 }
 
-static inline void fec_reset_phy(struct platform_device *pdev)
+static void fec_reset_phy(struct platform_device *pdev)
 {
        /*
         * In case of platform probe, the reset has been done
@@ -1570,10 +1750,17 @@ fec_probe(struct platform_device *pdev)
        /* setup board info structure */
        fep = netdev_priv(ndev);
 
+       /* default enable pause frame auto negotiation */
+       if (pdev->id_entry &&
+           (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
+               fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
+
        fep->hwp = ioremap(r->start, resource_size(r));
        fep->pdev = pdev;
        fep->dev_id = dev_id++;
 
+       fep->bufdesc_ex = 0;
+
        if (!fep->hwp) {
                ret = -ENOMEM;
                goto failed_ioremap;
@@ -1628,19 +1815,19 @@ fec_probe(struct platform_device *pdev)
                goto failed_clk;
        }
 
-#ifdef CONFIG_FEC_PTP
        fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
+       fep->bufdesc_ex =
+               pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
        if (IS_ERR(fep->clk_ptp)) {
                ret = PTR_ERR(fep->clk_ptp);
-               goto failed_clk;
+               fep->bufdesc_ex = 0;
        }
-#endif
 
        clk_prepare_enable(fep->clk_ahb);
        clk_prepare_enable(fep->clk_ipg);
-#ifdef CONFIG_FEC_PTP
-       clk_prepare_enable(fep->clk_ptp);
-#endif
+       if (!IS_ERR(fep->clk_ptp))
+               clk_prepare_enable(fep->clk_ptp);
+
        reg_phy = devm_regulator_get(&pdev->dev, "phy");
        if (!IS_ERR(reg_phy)) {
                ret = regulator_enable(reg_phy);
@@ -1668,9 +1855,8 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_register;
 
-#ifdef CONFIG_FEC_PTP
-       fec_ptp_init(ndev, pdev);
-#endif
+       if (fep->bufdesc_ex)
+               fec_ptp_init(ndev, pdev);
 
        return 0;
 
@@ -1681,9 +1867,8 @@ failed_init:
 failed_regulator:
        clk_disable_unprepare(fep->clk_ahb);
        clk_disable_unprepare(fep->clk_ipg);
-#ifdef CONFIG_FEC_PTP
-       clk_disable_unprepare(fep->clk_ptp);
-#endif
+       if (!IS_ERR(fep->clk_ptp))
+               clk_disable_unprepare(fep->clk_ptp);
 failed_pin:
 failed_clk:
        for (i = 0; i < FEC_IRQ_NUM; i++) {
@@ -1716,12 +1901,10 @@ fec_drv_remove(struct platform_device *pdev)
                if (irq > 0)
                        free_irq(irq, ndev);
        }
-#ifdef CONFIG_FEC_PTP
        del_timer_sync(&fep->time_keep);
        clk_disable_unprepare(fep->clk_ptp);
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
-#endif
        clk_disable_unprepare(fep->clk_ahb);
        clk_disable_unprepare(fep->clk_ipg);
        iounmap(fep->hwp);
index c5a3bc1475c7f58381b3ad654501a5a116821651..01579b8e37c4f979ea668b28538be4e22e255baa 100644 (file)
 #define        FEC_H
 /****************************************************************************/
 
-#ifdef CONFIG_FEC_PTP
 #include <linux/clocksource.h>
 #include <linux/net_tstamp.h>
 #include <linux/ptp_clock_kernel.h>
-#endif
 
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
     defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
 #define FEC_R_DES_START                0x180 /* Receive descriptor ring */
 #define FEC_X_DES_START                0x184 /* Transmit descriptor ring */
 #define FEC_R_BUFF_SIZE                0x188 /* Maximum receive buff size */
+#define FEC_R_FIFO_RSFL                0x190 /* Receive FIFO section full threshold */
+#define FEC_R_FIFO_RSEM                0x194 /* Receive FIFO section empty threshold */
+#define FEC_R_FIFO_RAEM                0x198 /* Receive FIFO almost empty threshold */
+#define FEC_R_FIFO_RAFL                0x19c /* Receive FIFO almost full threshold */
 #define FEC_MIIGSK_CFGR                0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR         0x308 /* MIIGSK Enable reg */
 
@@ -94,14 +96,17 @@ struct bufdesc {
        unsigned short cbd_datlen;      /* Data length */
        unsigned short cbd_sc;  /* Control and status info */
        unsigned long cbd_bufaddr;      /* Buffer address */
-#ifdef CONFIG_FEC_PTP
+};
+
+struct bufdesc_ex {
+       struct bufdesc desc;
        unsigned long cbd_esc;
        unsigned long cbd_prot;
        unsigned long cbd_bdu;
        unsigned long ts;
        unsigned short res0[4];
-#endif
 };
+
 #else
 struct bufdesc {
        unsigned short  cbd_sc;                 /* Control and status info */
@@ -203,9 +208,7 @@ struct fec_enet_private {
 
        struct clk *clk_ipg;
        struct clk *clk_ahb;
-#ifdef CONFIG_FEC_PTP
        struct clk *clk_ptp;
-#endif
 
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        unsigned char *tx_bounce[TX_RING_SIZE];
@@ -243,8 +246,11 @@ struct fec_enet_private {
        int     full_duplex;
        struct  completion mdio_done;
        int     irq[FEC_IRQ_NUM];
+       int     bufdesc_ex;
+       int     pause_flag;
+
+       struct  napi_struct napi;
 
-#ifdef CONFIG_FEC_PTP
        struct ptp_clock *ptp_clock;
        struct ptp_clock_info ptp_caps;
        unsigned long last_overflow_check;
@@ -257,15 +263,12 @@ struct fec_enet_private {
        int hwts_rx_en;
        int hwts_tx_en;
        struct timer_list time_keep;
-#endif
 
 };
 
-#ifdef CONFIG_FEC_PTP
 void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
 int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd);
-#endif
 
 /****************************************************************************/
 #endif /* FEC_H */
index e9879c5af7ba05dcea3364fb3db9c13d028998eb..46df28893c10649e0de42354671559b37bfef0c2 100644 (file)
@@ -888,8 +888,8 @@ static struct net_device_stats *fs_enet_get_stats(struct net_device *dev)
 static void fs_get_drvinfo(struct net_device *dev,
                            struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int fs_get_regs_len(struct net_device *dev)
index bffb2edd68584633aa8b5248fc27faf0990a05d5..19c54a0acb56938ad7ade3ac49e6bb769054b113 100644 (file)
@@ -355,6 +355,10 @@ static void gfar_init_mac(struct net_device *ndev)
                gfar_write(&regs->rir0, DEFAULT_RIR0);
        }
 
+       /* Restore PROMISC mode */
+       if (ndev->flags & IFF_PROMISC)
+               rctrl |= RCTRL_PROM;
+
        if (ndev->features & NETIF_F_RXCSUM)
                rctrl |= RCTRL_CHECKSUMMING;
 
@@ -540,6 +544,19 @@ static void unmap_group_regs(struct gfar_private *priv)
                        iounmap(priv->gfargrp[i].regs);
 }
 
+static void free_gfar_dev(struct gfar_private *priv)
+{
+       int i, j;
+
+       for (i = 0; i < priv->num_grps; i++)
+               for (j = 0; j < GFAR_NUM_IRQS; j++) {
+                       kfree(priv->gfargrp[i].irqinfo[j]);
+                       priv->gfargrp[i].irqinfo[j] = NULL;
+               }
+
+       free_netdev(priv->ndev);
+}
+
 static void disable_napi(struct gfar_private *priv)
 {
        int i;
@@ -559,40 +576,54 @@ static void enable_napi(struct gfar_private *priv)
 static int gfar_parse_group(struct device_node *np,
                            struct gfar_private *priv, const char *model)
 {
+       struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
        u32 *queue_mask;
+       int i;
 
-       priv->gfargrp[priv->num_grps].regs = of_iomap(np, 0);
-       if (!priv->gfargrp[priv->num_grps].regs)
+       if (priv->mode == MQ_MG_MODE) {
+               for (i = 0; i < GFAR_NUM_IRQS; i++) {
+                       grp->irqinfo[i] = kzalloc(sizeof(struct gfar_irqinfo),
+                                                 GFP_KERNEL);
+                       if (!grp->irqinfo[i])
+                               return -ENOMEM;
+               }
+       } else {
+               grp->irqinfo[GFAR_TX] = kzalloc(sizeof(struct gfar_irqinfo),
+                                               GFP_KERNEL);
+               if (!grp->irqinfo[GFAR_TX])
+                       return -ENOMEM;
+               grp->irqinfo[GFAR_RX] = grp->irqinfo[GFAR_ER] = NULL;
+       }
+
+       grp->regs = of_iomap(np, 0);
+       if (!grp->regs)
                return -ENOMEM;
 
-       priv->gfargrp[priv->num_grps].interruptTransmit =
-                       irq_of_parse_and_map(np, 0);
+       gfar_irq(grp, TX)->irq = irq_of_parse_and_map(np, 0);
 
        /* If we aren't the FEC we have multiple interrupts */
        if (model && strcasecmp(model, "FEC")) {
-               priv->gfargrp[priv->num_grps].interruptReceive =
-                       irq_of_parse_and_map(np, 1);
-               priv->gfargrp[priv->num_grps].interruptError =
-                       irq_of_parse_and_map(np,2);
-               if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ ||
-                   priv->gfargrp[priv->num_grps].interruptReceive  == NO_IRQ ||
-                   priv->gfargrp[priv->num_grps].interruptError    == NO_IRQ)
+               gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1);
+               gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
+               if (gfar_irq(grp, TX)->irq == NO_IRQ ||
+                   gfar_irq(grp, RX)->irq == NO_IRQ ||
+                   gfar_irq(grp, ER)->irq == NO_IRQ)
                        return -EINVAL;
        }
 
-       priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
-       priv->gfargrp[priv->num_grps].priv = priv;
-       spin_lock_init(&priv->gfargrp[priv->num_grps].grplock);
+       grp->grp_id = priv->num_grps;
+       grp->priv = priv;
+       spin_lock_init(&grp->grplock);
        if (priv->mode == MQ_MG_MODE) {
                queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
-               priv->gfargrp[priv->num_grps].rx_bit_map = queue_mask ?
+               grp->rx_bit_map = queue_mask ?
                        *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
                queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
-               priv->gfargrp[priv->num_grps].tx_bit_map = queue_mask ?
+               grp->tx_bit_map = queue_mask ?
                        *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
        } else {
-               priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF;
-               priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF;
+               grp->rx_bit_map = 0xFF;
+               grp->tx_bit_map = 0xFF;
        }
        priv->num_grps++;
 
@@ -777,7 +808,7 @@ tx_alloc_failed:
        free_tx_pointers(priv);
 err_grp_init:
        unmap_group_regs(priv);
-       free_netdev(dev);
+       free_gfar_dev(priv);
        return err;
 }
 
@@ -1182,15 +1213,16 @@ static int gfar_probe(struct platform_device *ofdev)
 
        /* fill out IRQ number and name fields */
        for (i = 0; i < priv->num_grps; i++) {
+               struct gfar_priv_grp *grp = &priv->gfargrp[i];
                if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-                       sprintf(priv->gfargrp[i].int_name_tx, "%s%s%c%s",
+                       sprintf(gfar_irq(grp, TX)->name, "%s%s%c%s",
                                dev->name, "_g", '0' + i, "_tx");
-                       sprintf(priv->gfargrp[i].int_name_rx, "%s%s%c%s",
+                       sprintf(gfar_irq(grp, RX)->name, "%s%s%c%s",
                                dev->name, "_g", '0' + i, "_rx");
-                       sprintf(priv->gfargrp[i].int_name_er, "%s%s%c%s",
+                       sprintf(gfar_irq(grp, ER)->name, "%s%s%c%s",
                                dev->name, "_g", '0' + i, "_er");
                } else
-                       strcpy(priv->gfargrp[i].int_name_tx, dev->name);
+                       strcpy(gfar_irq(grp, TX)->name, dev->name);
        }
 
        /* Initialize the filer table */
@@ -1223,7 +1255,7 @@ register_fail:
                of_node_put(priv->phy_node);
        if (priv->tbi_node)
                of_node_put(priv->tbi_node);
-       free_netdev(dev);
+       free_gfar_dev(priv);
        return err;
 }
 
@@ -1240,7 +1272,7 @@ static int gfar_remove(struct platform_device *ofdev)
 
        unregister_netdev(priv->ndev);
        unmap_group_regs(priv);
-       free_netdev(priv->ndev);
+       free_gfar_dev(priv);
 
        return 0;
 }
@@ -1648,9 +1680,9 @@ void gfar_halt(struct net_device *dev)
 
 static void free_grp_irqs(struct gfar_priv_grp *grp)
 {
-       free_irq(grp->interruptError, grp);
-       free_irq(grp->interruptTransmit, grp);
-       free_irq(grp->interruptReceive, grp);
+       free_irq(gfar_irq(grp, TX)->irq, grp);
+       free_irq(gfar_irq(grp, RX)->irq, grp);
+       free_irq(gfar_irq(grp, ER)->irq, grp);
 }
 
 void stop_gfar(struct net_device *dev)
@@ -1679,7 +1711,7 @@ void stop_gfar(struct net_device *dev)
                        free_grp_irqs(&priv->gfargrp[i]);
        } else {
                for (i = 0; i < priv->num_grps; i++)
-                       free_irq(priv->gfargrp[i].interruptTransmit,
+                       free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
                                 &priv->gfargrp[i]);
        }
 
@@ -1854,32 +1886,34 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                /* Install our interrupt handlers for Error,
                 * Transmit, and Receive
                 */
-               if ((err = request_irq(grp->interruptError, gfar_error,
-                                      0, grp->int_name_er, grp)) < 0) {
+               err = request_irq(gfar_irq(grp, ER)->irq, gfar_error, 0,
+                                 gfar_irq(grp, ER)->name, grp);
+               if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-                                 grp->interruptError);
+                                 gfar_irq(grp, ER)->irq);
 
                        goto err_irq_fail;
                }
-
-               if ((err = request_irq(grp->interruptTransmit, gfar_transmit,
-                                      0, grp->int_name_tx, grp)) < 0) {
+               err = request_irq(gfar_irq(grp, TX)->irq, gfar_transmit, 0,
+                                 gfar_irq(grp, TX)->name, grp);
+               if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-                                 grp->interruptTransmit);
+                                 gfar_irq(grp, TX)->irq);
                        goto tx_irq_fail;
                }
-
-               if ((err = request_irq(grp->interruptReceive, gfar_receive,
-                                      0, grp->int_name_rx, grp)) < 0) {
+               err = request_irq(gfar_irq(grp, RX)->irq, gfar_receive, 0,
+                                 gfar_irq(grp, RX)->name, grp);
+               if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-                                 grp->interruptReceive);
+                                 gfar_irq(grp, RX)->irq);
                        goto rx_irq_fail;
                }
        } else {
-               if ((err = request_irq(grp->interruptTransmit, gfar_interrupt,
-                                      0, grp->int_name_tx, grp)) < 0) {
+               err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
+                                 gfar_irq(grp, TX)->name, grp);
+               if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-                                 grp->interruptTransmit);
+                                 gfar_irq(grp, TX)->irq);
                        goto err_irq_fail;
                }
        }
@@ -1887,9 +1921,9 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
        return 0;
 
 rx_irq_fail:
-       free_irq(grp->interruptTransmit, grp);
+       free_irq(gfar_irq(grp, TX)->irq, grp);
 tx_irq_fail:
-       free_irq(grp->interruptError, grp);
+       free_irq(gfar_irq(grp, ER)->irq, grp);
 err_irq_fail:
        return err;
 
index 22eabc13ca99df900587678c24003167636446d3..71793f4fca32880fe6e8923a56370b4b3cb29a0d 100644 (file)
@@ -649,8 +649,6 @@ struct gfar_extra_stats {
 /* Number of stats in the stats structure (ignore car and cam regs)*/
 #define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN)
 
-#define GFAR_INFOSTR_LEN 32
-
 struct gfar_stats {
        u64 extra[GFAR_EXTRA_STATS_LEN];
        u64 rmon[GFAR_RMON_LEN];
@@ -937,26 +935,25 @@ struct tx_q_stats {
  *     @txtime: coalescing value if based on time
  */
 struct gfar_priv_tx_q {
+       /* cacheline 1 */
        spinlock_t txlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
-       struct sk_buff ** tx_skbuff;
-       /* Buffer descriptor pointers */
-       dma_addr_t tx_bd_dma_base;
        struct  txbd8 *tx_bd_base;
        struct  txbd8 *cur_tx;
-       struct  txbd8 *dirty_tx;
+       unsigned int num_txbdfree;
+       unsigned short skb_curtx;
+       unsigned short tx_ring_size;
        struct tx_q_stats stats;
-       struct  net_device *dev;
        struct gfar_priv_grp *grp;
-       u16     skb_curtx;
-       u16     skb_dirtytx;
-       u16     qindex;
-       unsigned int tx_ring_size;
-       unsigned int num_txbdfree;
+       /* cacheline 2 */
+       struct net_device *dev;
+       struct sk_buff **tx_skbuff;
+       struct  txbd8 *dirty_tx;
+       unsigned short skb_dirtytx;
+       unsigned short qindex;
        /* Configuration info for the coalescing features */
-       unsigned char txcoalescing;
+       unsigned int txcoalescing;
        unsigned long txic;
-       unsigned short txcount;
-       unsigned short txtime;
+       dma_addr_t tx_bd_dma_base;
 };
 
 /*
@@ -999,18 +996,25 @@ struct gfar_priv_rx_q {
        unsigned long rxic;
 };
 
+enum gfar_irqinfo_id {
+       GFAR_TX = 0,
+       GFAR_RX = 1,
+       GFAR_ER = 2,
+       GFAR_NUM_IRQS = 3
+};
+
+struct gfar_irqinfo {
+       unsigned int irq;
+       char name[GFAR_INT_NAME_MAX];
+};
+
 /**
  *     struct gfar_priv_grp - per group structure
  *     @napi: the napi poll function
  *     @priv: back pointer to the priv structure
  *     @regs: the ioremapped register space for this group
  *     @grp_id: group id for this group
- *     @interruptTransmit: The TX interrupt number for this group
- *     @interruptReceive: The RX interrupt number for this group
- *     @interruptError: The ERROR interrupt number for this group
- *     @int_name_tx: tx interrupt name for this group
- *     @int_name_rx: rx interrupt name for this group
- *     @int_name_er: er interrupt name for this group
+ *     @irqinfo: TX/RX/ER irq data for this group
  */
 
 struct gfar_priv_grp {
@@ -1019,23 +1023,20 @@ struct gfar_priv_grp {
        struct gfar_private *priv;
        struct gfar __iomem *regs;
        unsigned int grp_id;
-       unsigned long rx_bit_map;
-       unsigned long tx_bit_map;
-       unsigned long num_tx_queues;
        unsigned long num_rx_queues;
+       unsigned long rx_bit_map;
+       /* cacheline 3 */
        unsigned int rstat;
        unsigned int tstat;
-       unsigned int imask;
-       unsigned int ievent;
-       unsigned int interruptTransmit;
-       unsigned int interruptReceive;
-       unsigned int interruptError;
-
-       char int_name_tx[GFAR_INT_NAME_MAX];
-       char int_name_rx[GFAR_INT_NAME_MAX];
-       char int_name_er[GFAR_INT_NAME_MAX];
+       unsigned long num_tx_queues;
+       unsigned long tx_bit_map;
+
+       struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS];
 };
 
+#define gfar_irq(grp, ID) \
+       ((grp)->irqinfo[GFAR_##ID])
+
 enum gfar_errata {
        GFAR_ERRATA_74          = 0x01,
        GFAR_ERRATA_76          = 0x02,
@@ -1138,16 +1139,16 @@ static inline int gfar_has_errata(struct gfar_private *priv,
        return priv->errata & err;
 }
 
-static inline u32 gfar_read(volatile unsigned __iomem *addr)
+static inline u32 gfar_read(unsigned __iomem *addr)
 {
        u32 val;
-       val = in_be32(addr);
+       val = ioread32be(addr);
        return val;
 }
 
-static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
+static inline void gfar_write(unsigned __iomem *addr, u32 val)
 {
-       out_be32(addr, val);
+       iowrite32be(val, addr);
 }
 
 static inline void gfar_write_filer(struct gfar_private *priv,
index ab6762caa95702f492bbb457deae8986257bdcc4..d0fe53c5b297b0efdfa982d2af63691afa4260da 100644 (file)
@@ -184,10 +184,11 @@ static int gfar_sset_count(struct net_device *dev, int sset)
 static void gfar_gdrvinfo(struct net_device *dev,
                          struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
-       strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
-       strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
-       strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, gfar_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = 0;
        drvinfo->eedump_len = 0;
 }
index 37b035306013a0ac443040594177424e44a8422b..1ebf7128ec04da37a2236f41848bdad8b10162de 100644 (file)
@@ -350,10 +350,10 @@ static void
 uec_get_drvinfo(struct net_device *netdev,
                        struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver, DRV_NAME, 32);
-       strncpy(drvinfo->version, DRV_VERSION, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, "QUICC ENGINE", 32);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
        drvinfo->eedump_len = 0;
        drvinfo->regdump_len = uec_get_regs_len(netdev);
 }
index dffee9d44fd55ee13f2ba226c016f8b592eaac12..c6a87625898a18bf3b87c1841020d9bdc02ec515 100644 (file)
@@ -5,7 +5,7 @@
 config NET_VENDOR_FUJITSU
        bool "Fujitsu devices"
        default y
-       depends on ISA || PCMCIA || ((ISA || MCA_LEGACY) && EXPERIMENTAL)
+       depends on ISA || PCMCIA || (ISA && EXPERIMENTAL)
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
          and read the Ethernet-HOWTO, available from
@@ -17,18 +17,6 @@ config NET_VENDOR_FUJITSU
 
 if NET_VENDOR_FUJITSU
 
-config AT1700
-       tristate "AT1700/1720 support (EXPERIMENTAL)"
-       depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
-       select CRC32
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called at1700.
-
 config PCMCIA_FMVJ18X
        tristate "Fujitsu FMV-J18x PCMCIA support"
        depends on PCMCIA
@@ -40,15 +28,4 @@ config PCMCIA_FMVJ18X
          To compile this driver as a module, choose M here: the module will be
          called fmvj18x_cs.  If unsure, say N.
 
-config ETH16I
-       tristate "ICL EtherTeam 16i/32 support"
-       depends on ISA
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called eth16i.
-
 endif # NET_VENDOR_FUJITSU
index 2730ae67d3aa2028633ceb17557607b6b6e8ba76..21561fdcc69f75d1db9c716ca897d46c9b901019 100644 (file)
@@ -2,6 +2,4 @@
 # Makefile for the Fujitsu network device drivers.
 #
 
-obj-$(CONFIG_AT1700) += at1700.o
-obj-$(CONFIG_ETH16I) += eth16i.o
 obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o
diff --git a/drivers/net/ethernet/fujitsu/at1700.c b/drivers/net/ethernet/fujitsu/at1700.c
deleted file mode 100644 (file)
index 4b80dc4..0000000
+++ /dev/null
@@ -1,791 +0,0 @@
-/* at1700.c: A network device driver for  the Allied Telesis AT1700.
-
-       Written 1993-98 by Donald Becker.
-
-       Copyright 1993 United States Government as represented by the
-       Director, National Security Agency.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-       This is a device driver for the Allied Telesis AT1700, and
-        Fujitsu FMV-181/182/181A/182A/183/184/183A/184A, which are
-       straight-forward Fujitsu MB86965 implementations.
-
-       Modification for Fujitsu FMV-18X cards is done by Yutaka Tamiya
-       (tamy@flab.fujitsu.co.jp).
-
-  Sources:
-    The Fujitsu MB86965 datasheet.
-
-       After the initial version of this driver was written Gerry Sawkins of
-       ATI provided their EEPROM configuration code header file.
-    Thanks to NIIBE Yutaka <gniibe@mri.co.jp> for bug fixes.
-
-    MCA bus (AT1720) support (now deleted) by Rene Schmit <rene@bss.lu>
-
-  Bugs:
-       The MB86965 has a design flaw that makes all probes unreliable.  Not
-       only is it difficult to detect, it also moves around in I/O space in
-       response to inb()s from other device probes!
-*/
-
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/skbuff.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-static char version[] __initdata =
-       "at1700.c:v1.16 9/11/06  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#define DRV_NAME "at1700"
-
-/* Tunable parameters. */
-
-/* When to switch from the 64-entry multicast filter to Rx-all-multicast. */
-#define MC_FILTERBREAK 64
-
-/* These unusual address orders are used to verify the CONFIG register. */
-
-static int fmv18x_probe_list[] __initdata = {
-       0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
-};
-
-/*
- *     ISA
- */
-
-static unsigned at1700_probe_list[] __initdata = {
-       0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-typedef unsigned char uchar;
-
-/* Information that need to be kept for each board. */
-struct net_local {
-       spinlock_t lock;
-       unsigned char mc_filter[8];
-       uint jumpered:1;                        /* Set iff the board has jumper config. */
-       uint tx_started:1;                      /* Packets are on the Tx queue. */
-       uint tx_queue_ready:1;                  /* Tx queue is ready to be sent. */
-       uint rx_started:1;                      /* Packets are Rxing. */
-       uchar tx_queue;                         /* Number of packet on the Tx queue. */
-       ushort tx_queue_len;                    /* Current length of the Tx queue. */
-};
-
-
-/* Offsets from the base address. */
-#define STATUS                 0
-#define TX_STATUS              0
-#define RX_STATUS              1
-#define TX_INTR                        2               /* Bit-mapped interrupt enable registers. */
-#define RX_INTR                        3
-#define TX_MODE                        4
-#define RX_MODE                        5
-#define CONFIG_0               6               /* Misc. configuration settings. */
-#define CONFIG_1               7
-/* Run-time register bank 2 definitions. */
-#define DATAPORT               8               /* Word-wide DMA or programmed-I/O dataport. */
-#define TX_START               10
-#define COL16CNTL              11              /* Control Reg for 16 collisions */
-#define MODE13                 13
-#define RX_CTRL                        14
-/* Configuration registers only on the '865A/B chips. */
-#define EEPROM_Ctrl    16
-#define EEPROM_Data    17
-#define CARDSTATUS     16                      /* FMV-18x Card Status */
-#define CARDSTATUS1    17                      /* FMV-18x Card Status */
-#define IOCONFIG               18              /* Either read the jumper, or move the I/O. */
-#define IOCONFIG1              19
-#define        SAPROM                  20              /* The station address PROM, if no EEPROM. */
-#define MODE24                 24
-#define RESET                  31              /* Write to reset some parts of the chip. */
-#define AT1700_IO_EXTENT       32
-#define PORT_OFFSET(o) (o)
-
-
-#define TX_TIMEOUT             (HZ/10)
-
-
-/* Index to functions, as function prototypes. */
-
-static int at1700_probe1(struct net_device *dev, int ioaddr);
-static int read_eeprom(long ioaddr, int location);
-static int net_open(struct net_device *dev);
-static netdev_tx_t net_send_packet(struct sk_buff *skb,
-                                  struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id);
-static void net_rx(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static void net_tx_timeout (struct net_device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, allocate space for the device and return success
-   (detachable devices only).
-   */
-
-static int io = 0x260;
-
-static int irq;
-
-static void cleanup_card(struct net_device *dev)
-{
-       free_irq(dev->irq, NULL);
-       release_region(dev->base_addr, AT1700_IO_EXTENT);
-}
-
-struct net_device * __init at1700_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-       unsigned *port;
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-       } else {
-               dev->base_addr = io;
-               dev->irq = irq;
-       }
-
-       if (io > 0x1ff) {       /* Check a single specified location. */
-               err = at1700_probe1(dev, io);
-       } else if (io != 0) {   /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-               for (port = at1700_probe_list; *port; port++) {
-                       if (at1700_probe1(dev, *port) == 0)
-                               break;
-                       dev->irq = irq;
-               }
-               if (!*port)
-                       err = -ENODEV;
-       }
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       cleanup_card(dev);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops at1700_netdev_ops = {
-       .ndo_open               = net_open,
-       .ndo_stop               = net_close,
-       .ndo_start_xmit         = net_send_packet,
-       .ndo_set_rx_mode        = set_rx_mode,
-       .ndo_tx_timeout         = net_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
-   "signature", the default bit pattern after a reset.  This *doesn't* work --
-   there is no way to reset the bus interface without a complete power-cycle!
-
-   It turns out that ATI came to the same conclusion I did: the only thing
-   that can be done is checking a few bits and then diving right into an
-   EEPROM read. */
-
-static int __init at1700_probe1(struct net_device *dev, int ioaddr)
-{
-       static const char fmv_irqmap[4] = {3, 7, 10, 15};
-       static const char fmv_irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
-       static const char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
-       unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
-       int ret = -ENODEV;
-       struct net_local *lp = netdev_priv(dev);
-
-       if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
-               return -EBUSY;
-
-       /* Resetting the chip doesn't reset the ISA interface, so don't bother.
-          That means we have to be careful with the register values we probe
-          for.
-        */
-#ifdef notdef
-       printk("at1700 probe at %#x, eeprom is %4.4x %4.4x %4.4x ctrl %4.4x.\n",
-                  ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5),
-                  read_eeprom(ioaddr, 6), inw(ioaddr + EEPROM_Ctrl));
-#endif
-       /* We must check for the EEPROM-config boards first, else accessing
-          IOCONFIG0 will move the board! */
-       if (at1700_probe_list[inb(ioaddr + IOCONFIG1) & 0x07] == ioaddr &&
-           read_eeprom(ioaddr, 4) == 0x0000 &&
-           (read_eeprom(ioaddr, 5) & 0xff00) == 0xF400)
-               is_at1700 = 1;
-       else if (inb(ioaddr + SAPROM    ) == 0x00 &&
-                inb(ioaddr + SAPROM + 1) == 0x00 &&
-                inb(ioaddr + SAPROM + 2) == 0x0e)
-               is_fmv18x = 1;
-       else {
-               goto err_out;
-       }
-
-       /* Reset the internal state machines. */
-       outb(0, ioaddr + RESET);
-
-       if (is_at1700) {
-               irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
-                                                  | (read_eeprom(ioaddr, 0)>>14)];
-       } else {
-               /* Check PnP mode for FMV-183/184/183A/184A. */
-               /* This PnP routine is very poor. IO and IRQ should be known. */
-               if (inb(ioaddr + CARDSTATUS1) & 0x20) {
-                       irq = dev->irq;
-                       for (i = 0; i < 8; i++) {
-                               if (irq == fmv_irqmap_pnp[i])
-                                       break;
-                       }
-                       if (i == 8) {
-                               goto err_out;
-                       }
-               } else {
-                       if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
-                               goto err_out;
-                       irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
-               }
-       }
-
-       printk("%s: %s found at %#3x, IRQ %d, address ", dev->name,
-                  is_at1700 ? "AT1700" : "FMV-18X", ioaddr, irq);
-
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-
-       if (is_at1700) {
-               for(i = 0; i < 3; i++) {
-                       unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
-                       ((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val);
-               }
-       } else {
-               for(i = 0; i < 6; i++) {
-                       unsigned char val = inb(ioaddr + SAPROM + i);
-                       dev->dev_addr[i] = val;
-               }
-       }
-       printk("%pM", dev->dev_addr);
-
-       /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
-          rather than 150 ohm shielded twisted pair compensation.
-          0x0000 == auto-sense the interface
-          0x0800 == use TP interface
-          0x1800 == use coax interface
-          */
-       {
-               const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2"};
-               if (is_at1700) {
-                       ushort setup_value = read_eeprom(ioaddr, 12);
-                       dev->if_port = setup_value >> 8;
-               } else {
-                       ushort setup_value = inb(ioaddr + CARDSTATUS);
-                       switch (setup_value & 0x07) {
-                       case 0x01: /* 10base5 */
-                       case 0x02: /* 10base2 */
-                               dev->if_port = 0x18; break;
-                       case 0x04: /* 10baseT */
-                               dev->if_port = 0x08; break;
-                       default:   /* auto-sense */
-                               dev->if_port = 0x00; break;
-                       }
-               }
-               printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]);
-       }
-
-       /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
-          bus access, two 4K Tx queues, and disabled Tx and Rx. */
-       outb(0xda, ioaddr + CONFIG_0);
-
-       /* Set the station address in bank zero. */
-       outb(0x00, ioaddr + CONFIG_1);
-       for (i = 0; i < 6; i++)
-               outb(dev->dev_addr[i], ioaddr + PORT_OFFSET(8 + i));
-
-       /* Switch to bank 1 and set the multicast table to accept none. */
-       outb(0x04, ioaddr + CONFIG_1);
-       for (i = 0; i < 8; i++)
-               outb(0x00, ioaddr + PORT_OFFSET(8 + i));
-
-
-       /* Switch to bank 2 */
-       /* Lock our I/O address, and set manual processing mode for 16 collisions. */
-       outb(0x08, ioaddr + CONFIG_1);
-       outb(dev->if_port, ioaddr + MODE13);
-       outb(0x00, ioaddr + COL16CNTL);
-
-       if (net_debug)
-               printk(version);
-
-       dev->netdev_ops = &at1700_netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-
-       spin_lock_init(&lp->lock);
-
-       lp->jumpered = is_fmv18x;
-       /* Snarf the interrupt vector now. */
-       ret = request_irq(irq, net_interrupt, 0, DRV_NAME, dev);
-       if (ret) {
-               printk(KERN_ERR "AT1700 at %#3x is unusable due to a "
-                      "conflict on IRQ %d.\n",
-                      ioaddr, irq);
-               goto err_out;
-       }
-
-       return 0;
-
-err_out:
-       release_region(ioaddr, AT1700_IO_EXTENT);
-       return ret;
-}
-
-
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK   0x40    /* EEPROM shift clock, in reg. 16. */
-#define EE_CS                  0x20    /* EEPROM chip select, in reg. 16. */
-#define EE_DATA_WRITE  0x80    /* EEPROM chip data in, in reg. 17. */
-#define EE_DATA_READ   0x80    /* EEPROM chip data out, in reg. 17. */
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD   (5 << 6)
-#define EE_READ_CMD            (6 << 6)
-#define EE_ERASE_CMD   (7 << 6)
-
-static int __init read_eeprom(long ioaddr, int location)
-{
-       int i;
-       unsigned short retval = 0;
-       long ee_addr = ioaddr + EEPROM_Ctrl;
-       long ee_daddr = ioaddr + EEPROM_Data;
-       int read_cmd = location | EE_READ_CMD;
-
-       /* Shift the read command bits out. */
-       for (i = 9; i >= 0; i--) {
-               short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-               outb(EE_CS, ee_addr);
-               outb(dataval, ee_daddr);
-               outb(EE_CS | EE_SHIFT_CLK, ee_addr);    /* EEPROM clock tick. */
-       }
-       outb(EE_DATA_WRITE, ee_daddr);
-       for (i = 16; i > 0; i--) {
-               outb(EE_CS, ee_addr);
-               outb(EE_CS | EE_SHIFT_CLK, ee_addr);
-               retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
-       }
-
-       /* Terminate the EEPROM access. */
-       outb(EE_CS, ee_addr);
-       outb(EE_SHIFT_CLK, ee_addr);
-       outb(0, ee_addr);
-       return retval;
-}
-
-
-
-static int net_open(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
-          bus access, and two 4K Tx queues. */
-       outb(0x5a, ioaddr + CONFIG_0);
-
-       /* Powerup, switch to register bank 2, and enable the Rx and Tx. */
-       outb(0xe8, ioaddr + CONFIG_1);
-
-       lp->tx_started = 0;
-       lp->tx_queue_ready = 1;
-       lp->rx_started = 0;
-       lp->tx_queue = 0;
-       lp->tx_queue_len = 0;
-
-       /* Turn on hardware Tx and Rx interrupts. */
-       outb(0x82, ioaddr + TX_INTR);
-       outb(0x81, ioaddr + RX_INTR);
-
-       /* Enable the IRQ on boards of fmv18x it is feasible. */
-       if (lp->jumpered) {
-               outb(0x80, ioaddr + IOCONFIG1);
-       }
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-static void net_tx_timeout (struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       printk ("%s: transmit timed out with status %04x, %s?\n", dev->name,
-               inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
-               ? "IRQ conflict" : "network cable problem");
-       printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
-        dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
-               inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
-               inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
-       dev->stats.tx_errors++;
-       /* ToDo: We should try to restart the adaptor... */
-       outw(0xffff, ioaddr + MODE24);
-       outw (0xffff, ioaddr + TX_STATUS);
-       outb (0x5a, ioaddr + CONFIG_0);
-       outb (0xe8, ioaddr + CONFIG_1);
-       outw (0x8182, ioaddr + TX_INTR);
-       outb (0x00, ioaddr + TX_START);
-       outb (0x03, ioaddr + COL16CNTL);
-
-       dev->trans_start = jiffies; /* prevent tx timeout */
-
-       lp->tx_started = 0;
-       lp->tx_queue_ready = 1;
-       lp->rx_started = 0;
-       lp->tx_queue = 0;
-       lp->tx_queue_len = 0;
-
-       netif_wake_queue(dev);
-}
-
-
-static netdev_tx_t net_send_packet (struct sk_buff *skb,
-                                   struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-       short len = skb->len;
-       unsigned char *buf = skb->data;
-       static u8 pad[ETH_ZLEN];
-
-       netif_stop_queue (dev);
-
-       /* We may not start transmitting unless we finish transferring
-          a packet into the Tx queue. During executing the following
-          codes we possibly catch a Tx interrupt. Thus we flag off
-          tx_queue_ready, so that we prevent the interrupt routine
-          (net_interrupt) to start transmitting. */
-       lp->tx_queue_ready = 0;
-       {
-               outw (length, ioaddr + DATAPORT);
-               /* Packet data */
-               outsw (ioaddr + DATAPORT, buf, len >> 1);
-               /* Check for dribble byte */
-               if (len & 1) {
-                       outw(skb->data[skb->len-1], ioaddr + DATAPORT);
-                       len++;
-               }
-               /* Check for packet padding */
-               if (length != skb->len)
-                       outsw(ioaddr + DATAPORT, pad, (length - len + 1) >> 1);
-
-               lp->tx_queue++;
-               lp->tx_queue_len += length + 2;
-       }
-       lp->tx_queue_ready = 1;
-
-       if (lp->tx_started == 0) {
-               /* If the Tx is idle, always trigger a transmit. */
-               outb (0x80 | lp->tx_queue, ioaddr + TX_START);
-               lp->tx_queue = 0;
-               lp->tx_queue_len = 0;
-               lp->tx_started = 1;
-               netif_start_queue (dev);
-       } else if (lp->tx_queue_len < 4096 - 1502)
-               /* Yes, there is room for one more packet. */
-               netif_start_queue (dev);
-       dev_kfree_skb (skb);
-
-       return NETDEV_TX_OK;
-}
-
-/* The typical workload of the driver:
-   Handle the network interface interrupts. */
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct net_local *lp;
-       int ioaddr, status;
-       int handled = 0;
-
-       if (dev == NULL) {
-               printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
-               return IRQ_NONE;
-       }
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-
-       spin_lock (&lp->lock);
-
-       status = inw(ioaddr + TX_STATUS);
-       outw(status, ioaddr + TX_STATUS);
-
-       if (net_debug > 4)
-               printk("%s: Interrupt with status %04x.\n", dev->name, status);
-       if (lp->rx_started == 0 &&
-           (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
-               /* Got a packet(s).
-                  We cannot execute net_rx more than once at the same time for
-                  the same device. During executing net_rx, we possibly catch a
-                  Tx interrupt. Thus we flag on rx_started, so that we prevent
-                  the interrupt routine (net_interrupt) to dive into net_rx
-                  again. */
-               handled = 1;
-               lp->rx_started = 1;
-               outb(0x00, ioaddr + RX_INTR);   /* Disable RX intr. */
-               net_rx(dev);
-               outb(0x81, ioaddr + RX_INTR);   /* Enable  RX intr. */
-               lp->rx_started = 0;
-       }
-       if (status & 0x00ff) {
-               handled = 1;
-               if (status & 0x02) {
-                       /* More than 16 collisions occurred */
-                       if (net_debug > 4)
-                               printk("%s: 16 Collision occur during Txing.\n", dev->name);
-                       /* Cancel sending a packet. */
-                       outb(0x03, ioaddr + COL16CNTL);
-                       dev->stats.collisions++;
-               }
-               if (status & 0x82) {
-                       dev->stats.tx_packets++;
-                       /* The Tx queue has any packets and is not being
-                          transferred a packet from the host, start
-                          transmitting. */
-                       if (lp->tx_queue && lp->tx_queue_ready) {
-                               outb(0x80 | lp->tx_queue, ioaddr + TX_START);
-                               lp->tx_queue = 0;
-                               lp->tx_queue_len = 0;
-                               dev->trans_start = jiffies;
-                               netif_wake_queue (dev);
-                       } else {
-                               lp->tx_started = 0;
-                               netif_wake_queue (dev);
-                       }
-               }
-       }
-
-       spin_unlock (&lp->lock);
-       return IRQ_RETVAL(handled);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       int boguscount = 5;
-
-       while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
-               ushort status = inw(ioaddr + DATAPORT);
-               ushort pkt_len = inw(ioaddr + DATAPORT);
-
-               if (net_debug > 4)
-                       printk("%s: Rxing packet mode %02x status %04x.\n",
-                                  dev->name, inb(ioaddr + RX_MODE), status);
-#ifndef final_version
-               if (status == 0) {
-                       outb(0x05, ioaddr + RX_CTRL);
-                       break;
-               }
-#endif
-
-               if ((status & 0xF0) != 0x20) {  /* There was an error. */
-                       dev->stats.rx_errors++;
-                       if (status & 0x08) dev->stats.rx_length_errors++;
-                       if (status & 0x04) dev->stats.rx_frame_errors++;
-                       if (status & 0x02) dev->stats.rx_crc_errors++;
-                       if (status & 0x01) dev->stats.rx_over_errors++;
-               } else {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       if (pkt_len > 1550) {
-                               printk("%s: The AT1700 claimed a very large packet, size %d.\n",
-                                          dev->name, pkt_len);
-                               /* Prime the FIFO and then flush the packet. */
-                               inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
-                               outb(0x05, ioaddr + RX_CTRL);
-                               dev->stats.rx_errors++;
-                               break;
-                       }
-                       skb = netdev_alloc_skb(dev, pkt_len + 3);
-                       if (skb == NULL) {
-                               printk("%s: Memory squeeze, dropping packet (len %d).\n",
-                                          dev->name, pkt_len);
-                               /* Prime the FIFO and then flush the packet. */
-                               inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
-                               outb(0x05, ioaddr + RX_CTRL);
-                               dev->stats.rx_dropped++;
-                               break;
-                       }
-                       skb_reserve(skb,2);
-
-                       insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
-                       skb->protocol=eth_type_trans(skb, dev);
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-               }
-               if (--boguscount <= 0)
-                       break;
-       }
-
-       /* If any worth-while packets have been received, dev_rint()
-          has done a mark_bh(NET_BH) for us and will work on them
-          when we get to the bottom-half routine. */
-       {
-               int i;
-               for (i = 0; i < 20; i++) {
-                       if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
-                               break;
-                       inw(ioaddr + DATAPORT);                         /* dummy status read */
-                       outb(0x05, ioaddr + RX_CTRL);
-               }
-
-               if (net_debug > 5)
-                       printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
-                                  dev->name, inb(ioaddr + RX_MODE), i);
-       }
-}
-
-/* The inverse routine to net_open(). */
-static int net_close(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       netif_stop_queue(dev);
-
-       /* Set configuration register 0 to disable Tx and Rx. */
-       outb(0xda, ioaddr + CONFIG_0);
-
-       /* No statistic counters on the chip to update. */
-
-       /* Disable the IRQ on boards of fmv18x where it is feasible. */
-       if (lp->jumpered)
-               outb(0x00, ioaddr + IOCONFIG1);
-
-       /* Power-down the chip.  Green, green, green! */
-       outb(0x00, ioaddr + CONFIG_1);
-       return 0;
-}
-
-/*
-  Set the multicast/promiscuous mode for this adaptor.
-*/
-
-static void
-set_rx_mode(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct net_local *lp = netdev_priv(dev);
-       unsigned char mc_filter[8];              /* Multicast hash filter */
-       unsigned long flags;
-
-       if (dev->flags & IFF_PROMISC) {
-               memset(mc_filter, 0xff, sizeof(mc_filter));
-               outb(3, ioaddr + RX_MODE);      /* Enable promiscuous mode */
-       } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
-                          (dev->flags & IFF_ALLMULTI)) {
-               /* Too many to filter perfectly -- accept all multicasts. */
-               memset(mc_filter, 0xff, sizeof(mc_filter));
-               outb(2, ioaddr + RX_MODE);      /* Use normal mode. */
-       } else if (netdev_mc_empty(dev)) {
-               memset(mc_filter, 0x00, sizeof(mc_filter));
-               outb(1, ioaddr + RX_MODE);      /* Ignore almost all multicasts. */
-       } else {
-               struct netdev_hw_addr *ha;
-
-               memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(ha, dev) {
-                       unsigned int bit =
-                               ether_crc_le(ETH_ALEN, ha->addr) >> 26;
-                       mc_filter[bit >> 3] |= (1 << bit);
-               }
-               outb(0x02, ioaddr + RX_MODE);   /* Use normal mode. */
-       }
-
-       spin_lock_irqsave (&lp->lock, flags);
-       if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
-               int i;
-               int saved_bank = inw(ioaddr + CONFIG_0);
-               /* Switch to bank 1 and set the multicast table. */
-               outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
-               for (i = 0; i < 8; i++)
-                       outb(mc_filter[i], ioaddr + PORT_OFFSET(8 + i));
-               memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
-               outw(saved_bank, ioaddr + CONFIG_0);
-       }
-       spin_unlock_irqrestore (&lp->lock, flags);
-}
-
-#ifdef MODULE
-static struct net_device *dev_at1700;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(net_debug, int, 0);
-MODULE_PARM_DESC(io, "AT1700/FMV18X I/O base address");
-MODULE_PARM_DESC(irq, "AT1700/FMV18X IRQ number");
-MODULE_PARM_DESC(net_debug, "AT1700/FMV18X debug level (0-6)");
-
-static int __init at1700_module_init(void)
-{
-       if (io == 0)
-               printk("at1700: You should not use auto-probing with insmod!\n");
-       dev_at1700 = at1700_probe(-1);
-       if (IS_ERR(dev_at1700))
-               return PTR_ERR(dev_at1700);
-       return 0;
-}
-
-static void __exit at1700_module_exit(void)
-{
-       unregister_netdev(dev_at1700);
-       cleanup_card(dev_at1700);
-       free_netdev(dev_at1700);
-}
-module_init(at1700_module_init);
-module_exit(at1700_module_exit);
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/fujitsu/eth16i.c b/drivers/net/ethernet/fujitsu/eth16i.c
deleted file mode 100644 (file)
index a992d1f..0000000
+++ /dev/null
@@ -1,1483 +0,0 @@
-/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
-
-   Written 1994-1999 by Mika Kuoppala
-
-   Copyright (C) 1994-1999 by Mika Kuoppala
-   Based on skeleton.c and heavily on at1700.c by Donald Becker
-
-   This software may be used and distributed according to the terms
-   of the GNU General Public License, incorporated herein by reference.
-
-   The author may be reached as miku@iki.fi
-
-   This driver supports following cards :
-       - ICL EtherTeam 16i
-       - ICL EtherTeam 32 EISA
-         (Uses true 32 bit transfers rather than 16i compatibility mode)
-
-   Example Module usage:
-        insmod eth16i.o io=0x2a0 mediatype=bnc
-
-       mediatype can be one of the following: bnc,tp,dix,auto,eprom
-
-       'auto' will try to autoprobe mediatype.
-       'eprom' will use whatever type defined in eprom.
-
-   I have benchmarked driver with PII/300Mhz as a ftp client
-   and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
-
-   Sources:
-     - skeleton.c  a sample network driver core for linux,
-       written by Donald Becker <becker@scyld.com>
-     - at1700.c a driver for Allied Telesis AT1700, written
-       by Donald Becker.
-     - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
-       written by Markku Viima
-     - The Fujitsu MB86965 databook.
-
-   Author thanks following persons due to their valueble assistance:
-        Markku Viima (ICL)
-       Ari Valve (ICL)
-       Donald Becker
-       Kurt Huwig <kurt@huwig.de>
-
-   Revision history:
-
-   Version     Date            Description
-
-   0.01         15.12-94        Initial version (card detection)
-   0.02         23.01-95        Interrupt is now hooked correctly
-   0.03         01.02-95        Rewrote initialization part
-   0.04         07.02-95        Base skeleton done...
-                                Made a few changes to signature checking
-                                to make it a bit reliable.
-                                - fixed bug in tx_buf mapping
-                                - fixed bug in initialization (DLC_EN
-                                  wasn't enabled when initialization
-                                  was done.)
-   0.05         08.02-95        If there were more than one packet to send,
-                                transmit was jammed due to invalid
-                                register write...now fixed
-   0.06         19.02-95        Rewrote interrupt handling
-   0.07         13.04-95        Wrote EEPROM read routines
-                                Card configuration now set according to
-                                data read from EEPROM
-   0.08         23.06-95        Wrote part that tries to probe used interface
-                                port if AUTO is selected
-
-   0.09         01.09-95        Added module support
-
-   0.10         04.09-95        Fixed receive packet allocation to work
-                                with kernels > 1.3.x
-
-   0.20                20.09-95        Added support for EtherTeam32 EISA
-
-   0.21         17.10-95        Removed the unnecessary extern
-                               init_etherdev() declaration. Some
-                               other cleanups.
-
-   0.22                22.02-96        Receive buffer was not flushed
-                               correctly when faulty packet was
-                               received. Now fixed.
-
-   0.23                26.02-96        Made resetting the adapter
-                               more reliable.
-
-   0.24                27.02-96        Rewrote faulty packet handling in eth16i_rx
-
-   0.25                22.05-96        kfree() was missing from cleanup_module.
-
-   0.26                11.06-96        Sometimes card was not found by
-                               check_signature(). Now made more reliable.
-
-   0.27                23.06-96        Oops. 16 consecutive collisions halted
-                               adapter. Now will try to retransmit
-                               MAX_COL_16 times before finally giving up.
-
-   0.28                28.10-97        Added dev_id parameter (NULL) for free_irq
-
-   0.29         29.10-97        Multiple card support for module users
-
-   0.30         30.10-97        Fixed irq allocation bug.
-                                (request_irq moved from probe to open)
-
-   0.30a        21.08-98        Card detection made more relaxed. Driver
-                                had problems with some TCP/IP-PROM boots
-                               to find the card. Suggested by
-                               Kurt Huwig <kurt@huwig.de>
-
-   0.31         28.08-98        Media interface port can now be selected
-                                with module parameters or kernel
-                               boot parameters.
-
-   0.32         31.08-98        IRQ was never freed if open/close
-                                pair wasn't called. Now fixed.
-
-   0.33         10.09-98        When eth16i_open() was called after
-                                eth16i_close() chip never recovered.
-                               Now more shallow reset is made on
-                               close.
-
-   0.34         29.06-99       Fixed one bad #ifdef.
-                               Changed ioaddr -> io for consistency
-
-   0.35         01.07-99        transmit,-receive bytes were never
-                                updated in stats.
-
-   Bugs:
-       In some cases the media interface autoprobing code doesn't find
-       the correct interface type. In this case you can
-       manually choose the interface type in DOS with E16IC.EXE which is
-       configuration software for EtherTeam16i and EtherTeam32 cards.
-       This is also true for IRQ setting. You cannot use module
-       parameter to configure IRQ of the card (yet).
-
-   To do:
-       - Real multicast support
-       - Rewrite the media interface autoprobing code. Its _horrible_ !
-       - Possibly merge all the MB86965 specific code to external
-         module for use by eth16.c and Donald's at1700.c
-       - IRQ configuration with module parameter. I will do
-         this when i will get enough info about setting
-         irq without configuration utility.
-*/
-
-static char *version =
-    "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-
-
-
-/* Few macros */
-#define BITSET(ioaddr, bnum)   ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
-#define BITCLR(ioaddr, bnum)   ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
-
-/* This is the I/O address space for Etherteam 16i adapter. */
-#define ETH16I_IO_EXTENT       32
-
-/* Ticks before deciding that transmit has timed out */
-#define TX_TIMEOUT             (400*HZ/1000)
-
-/* Maximum loop count when receiving packets */
-#define MAX_RX_LOOP            20
-
-/* Some interrupt masks */
-#define ETH16I_INTR_ON        0xef8a       /* Higher is receive mask */
-#define ETH16I_INTR_OFF               0x0000
-
-/* Buffers header status byte meanings */
-#define PKT_GOOD               BIT(5)
-#define PKT_GOOD_RMT           BIT(4)
-#define PKT_SHORT              BIT(3)
-#define PKT_ALIGN_ERR          BIT(2)
-#define PKT_CRC_ERR            BIT(1)
-#define PKT_RX_BUF_OVERFLOW    BIT(0)
-
-/* Transmit status register (DLCR0) */
-#define TX_STATUS_REG          0
-#define TX_DONE                BIT(7)
-#define NET_BUSY               BIT(6)
-#define TX_PKT_RCD             BIT(5)
-#define CR_LOST                BIT(4)
-#define TX_JABBER_ERR         BIT(3)
-#define COLLISION              BIT(2)
-#define COLLISIONS_16          BIT(1)
-
-/* Receive status register (DLCR1) */
-#define RX_STATUS_REG          1
-#define RX_PKT                 BIT(7)  /* Packet received */
-#define BUS_RD_ERR             BIT(6)
-#define SHORT_PKT_ERR          BIT(3)
-#define ALIGN_ERR              BIT(2)
-#define CRC_ERR                BIT(1)
-#define RX_BUF_OVERFLOW        BIT(0)
-
-/* Transmit Interrupt Enable Register (DLCR2) */
-#define TX_INTR_REG            2
-#define TX_INTR_DONE           BIT(7)
-#define TX_INTR_COL            BIT(2)
-#define TX_INTR_16_COL         BIT(1)
-
-/* Receive Interrupt Enable Register (DLCR3) */
-#define RX_INTR_REG            3
-#define RX_INTR_RECEIVE        BIT(7)
-#define RX_INTR_SHORT_PKT      BIT(3)
-#define RX_INTR_CRC_ERR        BIT(1)
-#define RX_INTR_BUF_OVERFLOW   BIT(0)
-
-/* Transmit Mode Register (DLCR4) */
-#define TRANSMIT_MODE_REG      4
-#define LOOPBACK_CONTROL       BIT(1)
-#define CONTROL_OUTPUT         BIT(2)
-
-/* Receive Mode Register (DLCR5) */
-#define RECEIVE_MODE_REG       5
-#define RX_BUFFER_EMPTY        BIT(6)
-#define ACCEPT_BAD_PACKETS     BIT(5)
-#define RECEIVE_SHORT_ADDR     BIT(4)
-#define ACCEPT_SHORT_PACKETS   BIT(3)
-#define REMOTE_RESET           BIT(2)
-
-#define ADDRESS_FILTER_MODE    BIT(1) | BIT(0)
-#define REJECT_ALL             0
-#define ACCEPT_ALL             3
-#define MODE_1                 1            /* NODE ID, BC, MC, 2-24th bit */
-#define MODE_2                 2            /* NODE ID, BC, MC, Hash Table */
-
-/* Configuration Register 0 (DLCR6) */
-#define CONFIG_REG_0           6
-#define DLC_EN                 BIT(7)
-#define SRAM_CYCLE_TIME_100NS  BIT(6)
-#define SYSTEM_BUS_WIDTH_8     BIT(5)       /* 1 = 8bit, 0 = 16bit */
-#define BUFFER_WIDTH_8         BIT(4)       /* 1 = 8bit, 0 = 16bit */
-#define TBS1                   BIT(3)
-#define TBS0                   BIT(2)
-#define SRAM_BS1               BIT(1)       /* 00=8kb,  01=16kb  */
-#define SRAM_BS0               BIT(0)       /* 10=32kb, 11=64kb  */
-
-#ifndef ETH16I_TX_BUF_SIZE                   /* 0 = 2kb, 1 = 4kb  */
-#define ETH16I_TX_BUF_SIZE     3             /* 2 = 8kb, 3 = 16kb */
-#endif
-#define TX_BUF_1x2048          0
-#define TX_BUF_2x2048          1
-#define TX_BUF_2x4098          2
-#define TX_BUF_2x8192          3
-
-/* Configuration Register 1 (DLCR7) */
-#define CONFIG_REG_1           7
-#define POWERUP                BIT(5)
-
-/* Transmit start register */
-#define TRANSMIT_START_REG     10
-#define TRANSMIT_START_RB      2
-#define TX_START               BIT(7)       /* Rest of register bit indicate*/
-                                            /* number of packets in tx buffer*/
-/* Node ID registers (DLCR8-13) */
-#define NODE_ID_0              8
-#define NODE_ID_RB             0
-
-/* Hash Table registers (HT8-15) */
-#define HASH_TABLE_0           8
-#define HASH_TABLE_RB          1
-
-/* Buffer memory ports */
-#define BUFFER_MEM_PORT_LB     8
-#define DATAPORT               BUFFER_MEM_PORT_LB
-#define BUFFER_MEM_PORT_HB     9
-
-/* 16 Collision control register (BMPR11) */
-#define COL_16_REG             11
-#define HALT_ON_16             0x00
-#define RETRANS_AND_HALT_ON_16 0x02
-
-/* Maximum number of attempts to send after 16 concecutive collisions */
-#define MAX_COL_16            10
-
-/* DMA Burst and Transceiver Mode Register (BMPR13) */
-#define TRANSCEIVER_MODE_REG   13
-#define TRANSCEIVER_MODE_RB    2
-#define IO_BASE_UNLOCK        BIT(7)
-#define LOWER_SQUELCH_TRESH    BIT(6)
-#define LINK_TEST_DISABLE      BIT(5)
-#define AUI_SELECT             BIT(4)
-#define DIS_AUTO_PORT_SEL      BIT(3)
-
-/* Filter Self Receive Register (BMPR14)  */
-#define FILTER_SELF_RX_REG     14
-#define SKIP_RX_PACKET         BIT(2)
-#define FILTER_SELF_RECEIVE    BIT(0)
-
-/* EEPROM Control Register (BMPR 16) */
-#define EEPROM_CTRL_REG        16
-
-/* EEPROM Data Register (BMPR 17) */
-#define EEPROM_DATA_REG        17
-
-/* NMC93CSx6 EEPROM Control Bits */
-#define CS_0                   0x00
-#define CS_1                   0x20
-#define SK_0                   0x00
-#define SK_1                   0x40
-#define DI_0                   0x00
-#define DI_1                   0x80
-
-/* NMC93CSx6 EEPROM Instructions */
-#define EEPROM_READ            0x80
-
-/* NMC93CSx6 EEPROM Addresses */
-#define E_NODEID_0             0x02
-#define E_NODEID_1             0x03
-#define E_NODEID_2             0x04
-#define E_PORT_SELECT          0x14
-  #define E_PORT_BNC           0x00
-  #define E_PORT_DIX           0x01
-  #define E_PORT_TP            0x02
-  #define E_PORT_AUTO          0x03
-  #define E_PORT_FROM_EPROM    0x04
-#define E_PRODUCT_CFG          0x30
-
-
-/* Macro to slow down io between EEPROM clock transitions */
-#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
-
-/* Jumperless Configuration Register (BMPR19) */
-#define JUMPERLESS_CONFIG      19
-
-/* ID ROM registers, writing to them also resets some parts of chip */
-#define ID_ROM_0               24
-#define ID_ROM_7               31
-#define RESET                  ID_ROM_0
-
-/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] __initdata = {
-       0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
-
-static unsigned int eth32i_portlist[] __initdata = {
-       0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
-       0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
-};
-
-/* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 };
-#define NUM_OF_ISA_IRQS    4
-
-/* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
-#define EISA_IRQ_REG   0xc89
-#define NUM_OF_EISA_IRQS   8
-
-static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
-
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef ETH16I_DEBUG
-#define ETH16I_DEBUG 0
-#endif
-static unsigned int eth16i_debug = ETH16I_DEBUG;
-
-/* Information for each board */
-
-struct eth16i_local {
-       unsigned char     tx_started;
-       unsigned char     tx_buf_busy;
-       unsigned short    tx_queue;  /* Number of packets in transmit buffer */
-       unsigned short    tx_queue_len;
-       unsigned int      tx_buf_size;
-       unsigned long     open_time;
-       unsigned long     tx_buffered_packets;
-       unsigned long     tx_buffered_bytes;
-       unsigned long     col_16;
-       spinlock_t        lock;
-};
-
-/* Function prototypes */
-
-static int     eth16i_probe1(struct net_device *dev, int ioaddr);
-static int     eth16i_check_signature(int ioaddr);
-static int     eth16i_probe_port(int ioaddr);
-static void    eth16i_set_port(int ioaddr, int porttype);
-static int     eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l);
-static int     eth16i_receive_probe_packet(int ioaddr);
-static int     eth16i_get_irq(int ioaddr);
-static int     eth16i_read_eeprom(int ioaddr, int offset);
-static int     eth16i_read_eeprom_word(int ioaddr);
-static void    eth16i_eeprom_cmd(int ioaddr, unsigned char command);
-static int     eth16i_open(struct net_device *dev);
-static int     eth16i_close(struct net_device *dev);
-static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev);
-static void    eth16i_rx(struct net_device *dev);
-static void    eth16i_timeout(struct net_device *dev);
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id);
-static void    eth16i_reset(struct net_device *dev);
-static void    eth16i_timeout(struct net_device *dev);
-static void    eth16i_skip_packet(struct net_device *dev);
-static void    eth16i_multicast(struct net_device *dev);
-static void    eth16i_select_regbank(unsigned char regbank, int ioaddr);
-static void    eth16i_initialize(struct net_device *dev, int boot);
-
-#if 0
-static int     eth16i_set_irq(struct net_device *dev);
-#endif
-
-#ifdef MODULE
-static ushort  eth16i_parse_mediatype(const char* s);
-#endif
-
-static char cardname[] __initdata = "ICL EtherTeam 16i/32";
-
-static int __init do_eth16i_probe(struct net_device *dev)
-{
-       int i;
-       int ioaddr;
-       int base_addr = dev->base_addr;
-
-       if(eth16i_debug > 4)
-               printk(KERN_DEBUG "Probing started for %s\n", cardname);
-
-       if(base_addr > 0x1ff)           /* Check only single location */
-               return eth16i_probe1(dev, base_addr);
-       else if(base_addr != 0)         /* Don't probe at all */
-               return -ENXIO;
-
-       /* Seek card from the ISA io address space */
-       for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++)
-               if(eth16i_probe1(dev, ioaddr) == 0)
-                       return 0;
-
-       /* Seek card from the EISA io address space */
-       for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++)
-               if(eth16i_probe1(dev, ioaddr) == 0)
-                       return 0;
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eth16i_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_eth16i_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops eth16i_netdev_ops = {
-       .ndo_open               = eth16i_open,
-       .ndo_stop               = eth16i_close,
-       .ndo_start_xmit         = eth16i_tx,
-       .ndo_set_rx_mode        = eth16i_multicast,
-       .ndo_tx_timeout         = eth16i_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
-{
-       struct eth16i_local *lp = netdev_priv(dev);
-       static unsigned version_printed;
-       int retval;
-
-       /* Let's grab the region */
-       if (!request_region(ioaddr, ETH16I_IO_EXTENT, cardname))
-               return -EBUSY;
-
-       /*
-         The MB86985 chip has on register which holds information in which
-         io address the chip lies. First read this register and compare
-         it to our current io address and if match then this could
-         be our chip.
-         */
-
-       if(ioaddr < 0x1000) {
-               if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
-                  != ioaddr) {
-                       retval = -ENODEV;
-                       goto out;
-               }
-       }
-
-       /* Now we will go a bit deeper and try to find the chip's signature */
-
-       if(eth16i_check_signature(ioaddr) != 0) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       /*
-          Now it seems that we have found a ethernet chip in this particular
-          ioaddr. The MB86985 chip has this feature, that when you read a
-          certain register it will increase it's io base address to next
-          configurable slot. Now when we have found the chip, first thing is
-          to make sure that the chip's ioaddr will hold still here.
-          */
-
-       eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-       outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
-
-       outb(0x00, ioaddr + RESET);             /* Reset some parts of chip */
-       BITSET(ioaddr + CONFIG_REG_0, BIT(7));  /* Disable the data link */
-
-       if( (eth16i_debug & version_printed++) == 0)
-               printk(KERN_INFO "%s", version);
-
-       dev->base_addr = ioaddr;
-       dev->irq = eth16i_get_irq(ioaddr);
-
-       /* Try to obtain interrupt vector */
-
-       if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, cardname, dev))) {
-               printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n",
-                      cardname, ioaddr, dev->irq);
-               goto out;
-       }
-
-       printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
-              dev->name, cardname, ioaddr, dev->irq);
-
-
-       /* Now we will have to lock the chip's io address */
-       eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-       outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
-
-       eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */
-
-       /* Now let's same some energy by shutting down the chip ;) */
-       BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
-
-       /* Initialize the device structure */
-       dev->netdev_ops         = &eth16i_netdev_ops;
-       dev->watchdog_timeo     = TX_TIMEOUT;
-       spin_lock_init(&lp->lock);
-
-       retval = register_netdev(dev);
-       if (retval)
-               goto out1;
-       return 0;
-out1:
-       free_irq(dev->irq, dev);
-out:
-       release_region(ioaddr, ETH16I_IO_EXTENT);
-       return retval;
-}
-
-
-static void eth16i_initialize(struct net_device *dev, int boot)
-{
-       int ioaddr = dev->base_addr;
-       int i, node_w = 0;
-       unsigned char node_byte = 0;
-
-       /* Setup station address */
-       eth16i_select_regbank(NODE_ID_RB, ioaddr);
-       for(i = 0 ; i < 3 ; i++) {
-               unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
-               ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
-       }
-
-       for(i = 0; i < 6; i++) {
-               outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
-               if(boot) {
-                       printk("%02x", inb(ioaddr + NODE_ID_0 + i));
-                       if(i != 5)
-                               printk(":");
-               }
-       }
-
-       /* Now we will set multicast addresses to accept none */
-       eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
-       for(i = 0; i < 8; i++)
-               outb(0x00, ioaddr + HASH_TABLE_0 + i);
-
-       /*
-         Now let's disable the transmitter and receiver, set the buffer ram
-         cycle time, bus width and buffer data path width. Also we shall
-         set transmit buffer size and total buffer size.
-         */
-
-       eth16i_select_regbank(2, ioaddr);
-
-       node_byte = 0;
-       node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
-
-       if( (node_w & 0xFF00) == 0x0800)
-               node_byte |= BUFFER_WIDTH_8;
-
-       node_byte |= SRAM_BS1;
-
-       if( (node_w & 0x00FF) == 64)
-               node_byte |= SRAM_BS0;
-
-       node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
-
-       outb(node_byte, ioaddr + CONFIG_REG_0);
-
-       /* We shall halt the transmitting, if 16 collisions are detected */
-       outb(HALT_ON_16, ioaddr + COL_16_REG);
-
-#ifdef MODULE
-       /* if_port already set by init_module() */
-#else
-       dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
-               dev->mem_start : E_PORT_FROM_EPROM;
-#endif
-
-       /* Set interface port type */
-       if(boot) {
-               static const char * const porttype[] = {
-                       "BNC", "DIX", "TP", "AUTO", "FROM_EPROM"
-               };
-
-               switch(dev->if_port)
-               {
-
-               case E_PORT_FROM_EPROM:
-                       dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
-                       break;
-
-               case E_PORT_AUTO:
-                       dev->if_port = eth16i_probe_port(ioaddr);
-                       break;
-
-               case E_PORT_BNC:
-               case E_PORT_TP:
-               case E_PORT_DIX:
-                       break;
-               }
-
-               printk(" %s interface.\n", porttype[dev->if_port]);
-
-               eth16i_set_port(ioaddr, dev->if_port);
-       }
-
-       /* Set Receive Mode to normal operation */
-       outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
-}
-
-static int eth16i_probe_port(int ioaddr)
-{
-       int i;
-       int retcode;
-       unsigned char dummy_packet[64];
-
-       /* Powerup the chip */
-       outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
-       BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
-       eth16i_select_regbank(NODE_ID_RB, ioaddr);
-
-       for(i = 0; i < 6; i++) {
-               dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
-               dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
-       }
-
-       dummy_packet[12] = 0x00;
-       dummy_packet[13] = 0x04;
-       memset(dummy_packet + 14, 0, sizeof(dummy_packet) - 14);
-
-       eth16i_select_regbank(2, ioaddr);
-
-       for(i = 0; i < 3; i++) {
-               BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-               BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-               eth16i_set_port(ioaddr, i);
-
-               if(eth16i_debug > 1)
-                       printk(KERN_DEBUG "Set port number %d\n", i);
-
-               retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
-               if(retcode == 0) {
-                       retcode = eth16i_receive_probe_packet(ioaddr);
-                       if(retcode != -1) {
-                               if(eth16i_debug > 1)
-                                       printk(KERN_DEBUG "Eth16i interface port found at %d\n", i);
-                               return i;
-                       }
-               }
-               else {
-                       if(eth16i_debug > 1)
-                               printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n");
-               }
-       }
-
-       if( eth16i_debug > 1)
-               printk(KERN_DEBUG "Using default port\n");
-
-       return E_PORT_BNC;
-}
-
-static void eth16i_set_port(int ioaddr, int porttype)
-{
-       unsigned short temp = 0;
-
-       eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-       outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
-
-       temp |= DIS_AUTO_PORT_SEL;
-
-       switch(porttype) {
-
-       case E_PORT_BNC :
-               temp |= AUI_SELECT;
-               break;
-
-       case E_PORT_TP :
-               break;
-
-       case E_PORT_DIX :
-               temp |= AUI_SELECT;
-               BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
-               break;
-       }
-
-       outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
-
-       if(eth16i_debug > 1) {
-               printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
-               printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
-                      inb(ioaddr+TRANSCEIVER_MODE_REG));
-       }
-}
-
-static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
-{
-       unsigned long starttime;
-
-       outb(0xff, ioaddr + TX_STATUS_REG);
-
-       outw(l, ioaddr + DATAPORT);
-       outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
-
-       starttime = jiffies;
-       outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
-
-       while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
-               if( time_after(jiffies, starttime + TX_TIMEOUT)) {
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static int eth16i_receive_probe_packet(int ioaddr)
-{
-       unsigned long starttime;
-
-       starttime = jiffies;
-
-       while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
-               if( time_after(jiffies, starttime + TX_TIMEOUT)) {
-
-                       if(eth16i_debug > 1)
-                               printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n");
-                       starttime = jiffies;
-                       while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
-                               if( time_after(jiffies, starttime + TX_TIMEOUT)) {
-                                       if(eth16i_debug > 1)
-                                               printk(KERN_DEBUG "Timeout occurred waiting receive packet\n");
-                                       return -1;
-                               }
-                       }
-
-                       if(eth16i_debug > 1)
-                               printk(KERN_DEBUG "RECEIVE_PACKET\n");
-                       return 0; /* Found receive packet */
-               }
-       }
-
-       if(eth16i_debug > 1) {
-               printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
-               printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
-       }
-
-       return 0; /* Return success */
-}
-
-#if 0
-static int eth16i_set_irq(struct net_device* dev)
-{
-       const int ioaddr = dev->base_addr;
-       const int irq = dev->irq;
-       int i = 0;
-
-       if(ioaddr < 0x1000) {
-               while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
-                       i++;
-
-               if(i < NUM_OF_ISA_IRQS) {
-                       u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
-                       cbyte = (cbyte & 0x3F) | (i << 6);
-                       outb(cbyte, ioaddr + JUMPERLESS_CONFIG);
-                       return 0;
-               }
-       }
-       else {
-               printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
-       }
-
-       return -1;
-
-}
-#endif
-
-static int __init eth16i_get_irq(int ioaddr)
-{
-       unsigned char cbyte;
-
-       if( ioaddr < 0x1000) {
-               cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
-               return eth16i_irqmap[((cbyte & 0xC0) >> 6)];
-       } else {  /* Oh..the card is EISA so method getting IRQ different */
-               unsigned short index = 0;
-               cbyte = inb(ioaddr + EISA_IRQ_REG);
-               while( (cbyte & 0x01) == 0) {
-                       cbyte = cbyte >> 1;
-                       index++;
-               }
-               return eth32i_irqmap[index];
-       }
-}
-
-static int __init eth16i_check_signature(int ioaddr)
-{
-       int i;
-       unsigned char creg[4] = { 0 };
-
-       for(i = 0; i < 4 ; i++) {
-
-               creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
-
-               if(eth16i_debug > 1)
-                       printk("eth16i: read signature byte %x at %x\n",
-                              creg[i],
-                              ioaddr + TRANSMIT_MODE_REG + i);
-       }
-
-       creg[0] &= 0x0F;      /* Mask collision cnr */
-       creg[2] &= 0x7F;      /* Mask DCLEN bit */
-
-#if 0
-       /*
-          This was removed because the card was sometimes left to state
-          from which it couldn't be find anymore. If there is need
-          to more strict check still this have to be fixed.
-          */
-       if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) {
-               if(creg[1] != 0x42)
-                       return -1;
-       }
-#endif
-
-       if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
-               creg[2] &= 0x40;
-               creg[3] &= 0x03;
-
-               if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
-                       return -1;
-       }
-
-       if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
-               return -1;
-
-       if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
-               return -1;
-
-       return 0;
-}
-
-static int eth16i_read_eeprom(int ioaddr, int offset)
-{
-       int data = 0;
-
-       eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
-       outb(CS_1, ioaddr + EEPROM_CTRL_REG);
-       data = eth16i_read_eeprom_word(ioaddr);
-       outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
-
-       return data;
-}
-
-static int eth16i_read_eeprom_word(int ioaddr)
-{
-       int i;
-       int data = 0;
-
-       for(i = 16; i > 0; i--) {
-               outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-               eeprom_slow_io();
-               outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-               eeprom_slow_io();
-               data = (data << 1) |
-                       ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
-
-               eeprom_slow_io();
-       }
-
-       return data;
-}
-
-static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
-{
-       int i;
-
-       outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
-       outb(DI_0, ioaddr + EEPROM_DATA_REG);
-       outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-       outb(DI_1, ioaddr + EEPROM_DATA_REG);
-       outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-
-       for(i = 7; i >= 0; i--) {
-               short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
-               outb(cmd, ioaddr + EEPROM_DATA_REG);
-               outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-               eeprom_slow_io();
-               outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-               eeprom_slow_io();
-       }
-}
-
-static int eth16i_open(struct net_device *dev)
-{
-       struct eth16i_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       /* Powerup the chip */
-       outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
-       /* Initialize the chip */
-       eth16i_initialize(dev, 0);
-
-       /* Set the transmit buffer size */
-       lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
-
-       if(eth16i_debug > 0)
-               printk(KERN_DEBUG "%s: transmit buffer size %d\n",
-                      dev->name, lp->tx_buf_size);
-
-       /* Now enable Transmitter and Receiver sections */
-       BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-
-       /* Now switch to register bank 2, for run time operation */
-       eth16i_select_regbank(2, ioaddr);
-
-       lp->open_time = jiffies;
-       lp->tx_started = 0;
-       lp->tx_queue = 0;
-       lp->tx_queue_len = 0;
-
-       /* Turn on interrupts*/
-       outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-static int eth16i_close(struct net_device *dev)
-{
-       struct eth16i_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       eth16i_reset(dev);
-
-       /* Turn off interrupts*/
-       outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-       netif_stop_queue(dev);
-
-       lp->open_time = 0;
-
-       /* Disable transmit and receive */
-       BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
-       /* Reset the chip */
-       /* outb(0xff, ioaddr + RESET); */
-       /* outw(0xffff, ioaddr + TX_STATUS_REG);    */
-
-       outb(0x00, ioaddr + CONFIG_REG_1);
-
-       return 0;
-}
-
-static void eth16i_timeout(struct net_device *dev)
-{
-       struct eth16i_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       /*
-          If we get here, some higher level has decided that
-          we are broken. There should really be a "kick me"
-          function call instead.
-          */
-
-       outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-       printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
-              dev->name,
-       inw(ioaddr + TX_STATUS_REG),  (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
-                      "IRQ conflict" : "network cable problem");
-
-       dev->trans_start = jiffies; /* prevent tx timeout */
-
-       /* Let's dump all registers */
-       if(eth16i_debug > 0) {
-               printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
-                      dev->name, inb(ioaddr + 0),
-                      inb(ioaddr + 1), inb(ioaddr + 2),
-                      inb(ioaddr + 3), inb(ioaddr + 4),
-                      inb(ioaddr + 5),
-                      inb(ioaddr + 6), inb(ioaddr + 7));
-
-               printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
-                      dev->name, inb(ioaddr + TRANSMIT_START_REG),
-                      inb(ioaddr + COL_16_REG));
-                       printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
-               printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
-               printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
-       }
-       dev->stats.tx_errors++;
-       eth16i_reset(dev);
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-       netif_wake_queue(dev);
-}
-
-static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev)
-{
-       struct eth16i_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int status = 0;
-       ushort length = skb->len;
-       unsigned char *buf;
-       unsigned long flags;
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-       buf = skb->data;
-
-       netif_stop_queue(dev);
-
-       /* Turn off TX interrupts */
-       outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-       /* We would be better doing the disable_irq tricks the 3c509 does,
-          that would make this suck a lot less */
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
-               if(eth16i_debug > 0)
-                       printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
-       }
-       else {
-               outw(length, ioaddr + DATAPORT);
-
-               if( ioaddr < 0x1000 )
-                       outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-               else {
-                       unsigned char frag = length % 4;
-                       outsl(ioaddr + DATAPORT, buf, length >> 2);
-                       if( frag != 0 ) {
-                               outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
-                               if( frag == 3 )
-                                       outsw(ioaddr + DATAPORT,
-                                             (buf + (length & 0xFFFC) + 2), 1);
-                       }
-               }
-               lp->tx_buffered_packets++;
-               lp->tx_buffered_bytes = length;
-               lp->tx_queue++;
-               lp->tx_queue_len += length + 2;
-       }
-       lp->tx_buf_busy = 0;
-
-       if(lp->tx_started == 0) {
-               /* If the transmitter is idle..always trigger a transmit */
-               outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-               lp->tx_queue = 0;
-               lp->tx_queue_len = 0;
-               lp->tx_started = 1;
-               netif_wake_queue(dev);
-       }
-       else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
-               /* There is still more room for one more packet in tx buffer */
-               netif_wake_queue(dev);
-       }
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-       /* Turn TX interrupts back on */
-       /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
-       status = 0;
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-static void eth16i_rx(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       int boguscount = MAX_RX_LOOP;
-
-       /* Loop until all packets have been read */
-       while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
-
-               /* Read status byte from receive buffer */
-               ushort status = inw(ioaddr + DATAPORT);
-
-               /* Get the size of the packet from receive buffer */
-               ushort pkt_len = inw(ioaddr + DATAPORT);
-
-               if(eth16i_debug > 4)
-                       printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
-                              dev->name,
-                              inb(ioaddr + RECEIVE_MODE_REG), status);
-
-               if( !(status & PKT_GOOD) ) {
-                       dev->stats.rx_errors++;
-
-                       if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
-                               dev->stats.rx_length_errors++;
-                               eth16i_reset(dev);
-                               return;
-                       }
-                       else {
-                               eth16i_skip_packet(dev);
-                               dev->stats.rx_dropped++;
-                       }
-               }
-               else {   /* Ok so now we should have a good packet */
-                       struct sk_buff *skb;
-
-                       skb = netdev_alloc_skb(dev, pkt_len + 3);
-                       if( skb == NULL ) {
-                               printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
-                                      dev->name, pkt_len);
-                               eth16i_skip_packet(dev);
-                               dev->stats.rx_dropped++;
-                               break;
-                       }
-
-                       skb_reserve(skb,2);
-
-                       /*
-                          Now let's get the packet out of buffer.
-                          size is (pkt_len + 1) >> 1, cause we are now reading words
-                          and it have to be even aligned.
-                          */
-
-                       if(ioaddr < 0x1000)
-                               insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
-                                    (pkt_len + 1) >> 1);
-                       else {
-                               unsigned char *buf = skb_put(skb, pkt_len);
-                               unsigned char frag = pkt_len % 4;
-
-                               insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
-
-                               if(frag != 0) {
-                                       unsigned short rest[2];
-                                       rest[0] = inw( ioaddr + DATAPORT );
-                                       if(frag == 3)
-                                               rest[1] = inw( ioaddr + DATAPORT );
-
-                                       memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
-                               }
-                       }
-
-                       skb->protocol=eth_type_trans(skb, dev);
-
-                       if( eth16i_debug > 5 ) {
-                               int i;
-                               printk(KERN_DEBUG "%s: Received packet of length %d.\n",
-                                      dev->name, pkt_len);
-                               for(i = 0; i < 14; i++)
-                                       printk(KERN_DEBUG " %02x", skb->data[i]);
-                               printk(KERN_DEBUG ".\n");
-                       }
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-
-               } /* else */
-
-               if(--boguscount <= 0)
-                       break;
-
-       } /* while */
-}
-
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct eth16i_local *lp;
-       int ioaddr = 0, status;
-       int handled = 0;
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-
-       /* Turn off all interrupts from adapter */
-       outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-       /* eth16i_tx won't be called */
-       spin_lock(&lp->lock);
-
-       status = inw(ioaddr + TX_STATUS_REG);      /* Get the status */
-       outw(status, ioaddr + TX_STATUS_REG);      /* Clear status bits */
-
-       if (status)
-               handled = 1;
-
-       if(eth16i_debug > 3)
-               printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status);
-
-       if( status & 0x7f00 ) {
-
-               dev->stats.rx_errors++;
-
-               if(status & (BUS_RD_ERR << 8) )
-                       printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
-               if(status & (SHORT_PKT_ERR << 8) )   dev->stats.rx_length_errors++;
-               if(status & (ALIGN_ERR << 8) )       dev->stats.rx_frame_errors++;
-               if(status & (CRC_ERR << 8) )        dev->stats.rx_crc_errors++;
-               if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++;
-       }
-       if( status & 0x001a) {
-
-               dev->stats.tx_errors++;
-
-               if(status & CR_LOST) dev->stats.tx_carrier_errors++;
-               if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++;
-
-#if 0
-               if(status & COLLISION) {
-                       dev->stats.collisions +=
-                               ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
-               }
-#endif
-               if(status & COLLISIONS_16) {
-                       if(lp->col_16 < MAX_COL_16) {
-                               lp->col_16++;
-                               dev->stats.collisions++;
-                               /* Resume transmitting, skip failed packet */
-                               outb(0x02, ioaddr + COL_16_REG);
-                       }
-                       else {
-                               printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name);
-                       }
-               }
-       }
-
-       if( status & 0x00ff ) {          /* Let's check the transmit status reg */
-
-               if(status & TX_DONE) {         /* The transmit has been done */
-                       dev->stats.tx_packets = lp->tx_buffered_packets;
-                       dev->stats.tx_bytes += lp->tx_buffered_bytes;
-                       lp->col_16 = 0;
-
-                       if(lp->tx_queue) {           /* Is there still packets ? */
-                               /* There was packet(s) so start transmitting and write also
-                                  how many packets there is to be sended */
-                               outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-                               lp->tx_queue = 0;
-                               lp->tx_queue_len = 0;
-                               lp->tx_started = 1;
-                       }
-                       else {
-                               lp->tx_started = 0;
-                       }
-                       netif_wake_queue(dev);
-               }
-       }
-
-       if( ( status & 0x8000 ) ||
-           ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
-               eth16i_rx(dev);  /* We have packet in receive buffer */
-       }
-
-       /* Turn interrupts back on */
-       outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
-       if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
-               /* There is still more room for one more packet in tx buffer */
-               netif_wake_queue(dev);
-       }
-
-       spin_unlock(&lp->lock);
-
-       return IRQ_RETVAL(handled);
-}
-
-static void eth16i_skip_packet(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       inw(ioaddr + DATAPORT);
-       inw(ioaddr + DATAPORT);
-       inw(ioaddr + DATAPORT);
-
-       outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
-       while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0);
-}
-
-static void eth16i_reset(struct net_device *dev)
-{
-       struct eth16i_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       if(eth16i_debug > 1)
-               printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
-
-       BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-       outw(0xffff, ioaddr + TX_STATUS_REG);
-       eth16i_select_regbank(2, ioaddr);
-
-       lp->tx_started = 0;
-       lp->tx_buf_busy = 0;
-       lp->tx_queue = 0;
-       lp->tx_queue_len = 0;
-       BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-}
-
-static void eth16i_multicast(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
-       {
-               outb(3, ioaddr + RECEIVE_MODE_REG);
-       } else {
-               outb(2, ioaddr + RECEIVE_MODE_REG);
-       }
-}
-
-static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
-{
-       unsigned char data;
-
-       data = inb(ioaddr + CONFIG_REG_1);
-       outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
-}
-
-#ifdef MODULE
-
-static ushort eth16i_parse_mediatype(const char* s)
-{
-       if(!s)
-               return E_PORT_FROM_EPROM;
-
-        if (!strncmp(s, "bnc", 3))
-               return E_PORT_BNC;
-        else if (!strncmp(s, "tp", 2))
-                return E_PORT_TP;
-        else if (!strncmp(s, "dix", 3))
-                return E_PORT_DIX;
-        else if (!strncmp(s, "auto", 4))
-               return E_PORT_AUTO;
-       else
-               return E_PORT_FROM_EPROM;
-}
-
-#define MAX_ETH16I_CARDS 4  /* Max number of Eth16i cards per module */
-
-static struct net_device *dev_eth16i[MAX_ETH16I_CARDS];
-static int io[MAX_ETH16I_CARDS];
-#if 0
-static int irq[MAX_ETH16I_CARDS];
-#endif
-static char* mediatype[MAX_ETH16I_CARDS];
-static int debug = -1;
-
-MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
-MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
-MODULE_LICENSE("GPL");
-
-
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "eth16i I/O base address(es)");
-
-#if 0
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq, "eth16i interrupt request number");
-#endif
-
-module_param_array(mediatype, charp, NULL, 0);
-MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto,eprom)");
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "eth16i debug level (0-6)");
-
-int __init init_module(void)
-{
-       int this_dev, found = 0;
-       struct net_device *dev;
-
-       for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
-               dev = alloc_etherdev(sizeof(struct eth16i_local));
-               if (!dev)
-                       break;
-
-               dev->base_addr = io[this_dev];
-
-               if(debug != -1)
-                       eth16i_debug = debug;
-
-               if(eth16i_debug > 1)
-                       printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" );
-
-               dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
-
-               if(io[this_dev] == 0) {
-                       if (this_dev != 0) { /* Only autoprobe 1st one */
-                               free_netdev(dev);
-                               break;
-                       }
-
-                       printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
-               }
-
-               if (do_eth16i_probe(dev) == 0) {
-                       dev_eth16i[found++] = dev;
-                       continue;
-               }
-               printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
-                      io[this_dev]);
-               free_netdev(dev);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-
-       for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
-               struct net_device *dev = dev_eth16i[this_dev];
-
-               if (netdev_priv(dev)) {
-                       unregister_netdev(dev);
-                       free_irq(dev->irq, dev);
-                       release_region(dev->base_addr, ETH16I_IO_EXTENT);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/3c505.c b/drivers/net/ethernet/i825xx/3c505.c
deleted file mode 100644 (file)
index 6a5c21b..0000000
+++ /dev/null
@@ -1,1671 +0,0 @@
-/*
- * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
- *      By Craig Southeren, Juha Laiho and Philip Blundell
- *
- * 3c505.c      This module implements an interface to the 3Com
- *              Etherlink Plus (3c505) Ethernet card. Linux device
- *              driver interface reverse engineered from the Linux 3C509
- *              device drivers. Some 3C505 information gleaned from
- *              the Crynwr packet driver. Still this driver would not
- *              be here without 3C505 technical reference provided by
- *              3Com.
- *
- * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
- *
- * Authors:     Linux 3c505 device driver by
- *                      Craig Southeren, <craigs@ineluki.apana.org.au>
- *              Final debugging by
- *                      Andrew Tridgell, <tridge@nimbus.anu.edu.au>
- *              Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
- *                      Juha Laiho, <jlaiho@ichaos.nullnet.fi>
- *              Linux 3C509 driver by
- *                      Donald Becker, <becker@super.org>
- *                     (Now at <becker@scyld.com>)
- *              Crynwr packet driver by
- *                      Krishnan Gopalan and Gregg Stefancik,
- *                      Clemson University Engineering Computer Operations.
- *                      Portions of the code have been adapted from the 3c505
- *                         driver for NCSA Telnet by Bruce Orchard and later
- *                         modified by Warren Van Houten and krus@diku.dk.
- *              3C505 technical information provided by
- *                      Terry Murphy, of 3Com Network Adapter Division
- *              Linux 1.3.0 changes by
- *                      Alan Cox <Alan.Cox@linux.org>
- *              More debugging, DMA support, currently maintained by
- *                      Philip Blundell <philb@gnu.org>
- *              Multicard/soft configurable dma channel/rev 2 hardware support
- *                      by Christopher Collins <ccollins@pcug.org.au>
- *             Ethtool support (jgarzik), 11/17/2001
- */
-
-#define DRV_NAME       "3c505"
-#define DRV_VERSION    "1.10a"
-
-
-/* Theory of operation:
- *
- * The 3c505 is quite an intelligent board.  All communication with it is done
- * by means of Primary Command Blocks (PCBs); these are transferred using PIO
- * through the command register.  The card has 256k of on-board RAM, which is
- * used to buffer received packets.  It might seem at first that more buffers
- * are better, but in fact this isn't true.  From my tests, it seems that
- * more than about 10 buffers are unnecessary, and there is a noticeable
- * performance hit in having more active on the card.  So the majority of the
- * card's memory isn't, in fact, used.  Sadly, the card only has one transmit
- * buffer and, short of loading our own firmware into it (which is what some
- * drivers resort to) there's nothing we can do about this.
- *
- * We keep up to 4 "receive packet" commands active on the board at a time.
- * When a packet comes in, so long as there is a receive command active, the
- * board will send us a "packet received" PCB and then add the data for that
- * packet to the DMA queue.  If a DMA transfer is not already in progress, we
- * set one up to start uploading the data.  We have to maintain a list of
- * backlogged receive packets, because the card may decide to tell us about
- * a newly-arrived packet at any time, and we may not be able to start a DMA
- * transfer immediately (ie one may already be going on).  We can't NAK the
- * PCB, because then it would throw the packet away.
- *
- * Trying to send a PCB to the card at the wrong moment seems to have bad
- * effects.  If we send it a transmit PCB while a receive DMA is happening,
- * it will just NAK the PCB and so we will have wasted our time.  Worse, it
- * sometimes seems to interrupt the transfer.  The majority of the low-level
- * code is protected by one huge semaphore -- "busy" -- which is set whenever
- * it probably isn't safe to do anything to the card.  The receive routine
- * must gain a lock on "busy" before it can start a DMA transfer, and the
- * transmit routine must gain a lock before it sends the first PCB to the card.
- * The send_pcb() routine also has an internal semaphore to protect it against
- * being re-entered (which would be disastrous) -- this is needed because
- * several things can happen asynchronously (re-priming the receiver and
- * asking the card for statistics, for example).  send_pcb() will also refuse
- * to talk to the card at all if a DMA upload is happening.  The higher-level
- * networking code will reschedule a later retry if some part of the driver
- * is blocked.  In practice, this doesn't seem to happen very often.
- */
-
-/* This driver may now work with revision 2.x hardware, since all the read
- * operations on the HCR have been removed (we now keep our own softcopy).
- * But I don't have an old card to test it on.
- *
- * This has had the bad effect that the autoprobe routine is now a bit
- * less friendly to other devices.  However, it was never very good.
- * before, so I doubt it will hurt anybody.
- */
-
-/* The driver is a mess.  I took Craig's and Juha's code, and hacked it firstly
- * to make it more reliable, and secondly to add DMA mode.  Many things could
- * probably be done better; the concurrency protection is particularly awful.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c505.h"
-
-/*********************************************************
- *
- *  define debug messages here as common strings to reduce space
- *
- *********************************************************/
-
-#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
-#define TIMEOUT_MSG(lineno) \
-       pr_notice(timeout_msg, __FILE__, __func__, (lineno))
-
-#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
-#define INVALID_PCB_MSG(len) \
-       pr_notice(invalid_pcb_msg, (len), __FILE__, __func__, __LINE__)
-
-#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
-
-#define stilllooking_msg "still looking..."
-
-#define found_msg "found.\n"
-
-#define notfound_msg "not found (reason = %d)\n"
-
-#define couldnot_msg "%s: 3c505 not found\n"
-
-/*********************************************************
- *
- *  various other debug stuff
- *
- *********************************************************/
-
-#ifdef ELP_DEBUG
-static int elp_debug = ELP_DEBUG;
-#else
-static int elp_debug;
-#endif
-#define debug elp_debug
-
-/*
- *  0 = no messages (well, some)
- *  1 = messages when high level commands performed
- *  2 = messages when low level commands performed
- *  3 = messages when interrupts received
- */
-
-/*****************************************************************
- *
- * List of I/O-addresses we try to auto-sense
- * Last element MUST BE 0!
- *****************************************************************/
-
-static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
-
-/* Dma Memory related stuff */
-
-static unsigned long dma_mem_alloc(int size)
-{
-       int order = get_order(size);
-       return __get_dma_pages(GFP_KERNEL, order);
-}
-
-
-/*****************************************************************
- *
- * Functions for I/O (note the inline !)
- *
- *****************************************************************/
-
-static inline unsigned char inb_status(unsigned int base_addr)
-{
-       return inb(base_addr + PORT_STATUS);
-}
-
-static inline int inb_command(unsigned int base_addr)
-{
-       return inb(base_addr + PORT_COMMAND);
-}
-
-static inline void outb_control(unsigned char val, struct net_device *dev)
-{
-       outb(val, dev->base_addr + PORT_CONTROL);
-       ((elp_device *)(netdev_priv(dev)))->hcr_val = val;
-}
-
-#define HCR_VAL(x)   (((elp_device *)(netdev_priv(x)))->hcr_val)
-
-static inline void outb_command(unsigned char val, unsigned int base_addr)
-{
-       outb(val, base_addr + PORT_COMMAND);
-}
-
-static inline unsigned int backlog_next(unsigned int n)
-{
-       return (n + 1) % BACKLOG_SIZE;
-}
-
-/*****************************************************************
- *
- *  useful functions for accessing the adapter
- *
- *****************************************************************/
-
-/*
- * use this routine when accessing the ASF bits as they are
- * changed asynchronously by the adapter
- */
-
-/* get adapter PCB status */
-#define        GET_ASF(addr) \
-       (get_status(addr)&ASF_PCB_MASK)
-
-static inline int get_status(unsigned int base_addr)
-{
-       unsigned long timeout = jiffies + 10*HZ/100;
-       register int stat1;
-       do {
-               stat1 = inb_status(base_addr);
-       } while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
-       if (time_after_eq(jiffies, timeout))
-               TIMEOUT_MSG(__LINE__);
-       return stat1;
-}
-
-static inline void set_hsf(struct net_device *dev, int hsf)
-{
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&adapter->lock, flags);
-       outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
-       spin_unlock_irqrestore(&adapter->lock, flags);
-}
-
-static bool start_receive(struct net_device *, pcb_struct *);
-
-static inline void adapter_reset(struct net_device *dev)
-{
-       unsigned long timeout;
-       elp_device *adapter = netdev_priv(dev);
-       unsigned char orig_hcr = adapter->hcr_val;
-
-       outb_control(0, dev);
-
-       if (inb_status(dev->base_addr) & ACRF) {
-               do {
-                       inb_command(dev->base_addr);
-                       timeout = jiffies + 2*HZ/100;
-                       while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
-               } while (inb_status(dev->base_addr) & ACRF);
-               set_hsf(dev, HSF_PCB_NAK);
-       }
-       outb_control(adapter->hcr_val | ATTN | DIR, dev);
-       mdelay(10);
-       outb_control(adapter->hcr_val & ~ATTN, dev);
-       mdelay(10);
-       outb_control(adapter->hcr_val | FLSH, dev);
-       mdelay(10);
-       outb_control(adapter->hcr_val & ~FLSH, dev);
-       mdelay(10);
-
-       outb_control(orig_hcr, dev);
-       if (!start_receive(dev, &adapter->tx_pcb))
-               pr_err("%s: start receive command failed\n", dev->name);
-}
-
-/* Check to make sure that a DMA transfer hasn't timed out.  This should
- * never happen in theory, but seems to occur occasionally if the card gets
- * prodded at the wrong time.
- */
-static inline void check_3c505_dma(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
-               unsigned long flags, f;
-               pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name,
-                       adapter->current_dma.direction ? "download" : "upload",
-                       get_dma_residue(dev->dma));
-               spin_lock_irqsave(&adapter->lock, flags);
-               adapter->dmaing = 0;
-               adapter->busy = 0;
-
-               f=claim_dma_lock();
-               disable_dma(dev->dma);
-               release_dma_lock(f);
-
-               if (adapter->rx_active)
-                       adapter->rx_active--;
-               outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
-               spin_unlock_irqrestore(&adapter->lock, flags);
-       }
-}
-
-/* Primitive functions used by send_pcb() */
-static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
-{
-       unsigned long timeout;
-       outb_command(byte, base_addr);
-       for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
-               if (inb_status(base_addr) & HCRE)
-                       return false;
-       }
-       pr_warning("3c505: send_pcb_slow timed out\n");
-       return true;
-}
-
-static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
-{
-       unsigned int timeout;
-       outb_command(byte, base_addr);
-       for (timeout = 0; timeout < 40000; timeout++) {
-               if (inb_status(base_addr) & HCRE)
-                       return false;
-       }
-       pr_warning("3c505: send_pcb_fast timed out\n");
-       return true;
-}
-
-/* Check to see if the receiver needs restarting, and kick it if so */
-static inline void prime_rx(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
-               if (!start_receive(dev, &adapter->itx_pcb))
-                       break;
-       }
-}
-
-/*****************************************************************
- *
- * send_pcb
- *   Send a PCB to the adapter.
- *
- *     output byte to command reg  --<--+
- *     wait until HCRE is non zero      |
- *     loop until all bytes sent   -->--+
- *     set HSF1 and HSF2 to 1
- *     output pcb length
- *     wait until ASF give ACK or NAK
- *     set HSF1 and HSF2 to 0
- *
- *****************************************************************/
-
-/* This can be quite slow -- the adapter is allowed to take up to 40ms
- * to respond to the initial interrupt.
- *
- * We run initially with interrupts turned on, but with a semaphore set
- * so that nobody tries to re-enter this code.  Once the first byte has
- * gone through, we turn interrupts off and then send the others (the
- * timeout is reduced to 500us).
- */
-
-static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
-{
-       int i;
-       unsigned long timeout;
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long flags;
-
-       check_3c505_dma(dev);
-
-       if (adapter->dmaing && adapter->current_dma.direction == 0)
-               return false;
-
-       /* Avoid contention */
-       if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
-               if (elp_debug >= 3) {
-                       pr_debug("%s: send_pcb entered while threaded\n", dev->name);
-               }
-               return false;
-       }
-       /*
-        * load each byte into the command register and
-        * wait for the HCRE bit to indicate the adapter
-        * had read the byte
-        */
-       set_hsf(dev, 0);
-
-       if (send_pcb_slow(dev->base_addr, pcb->command))
-               goto abort;
-
-       spin_lock_irqsave(&adapter->lock, flags);
-
-       if (send_pcb_fast(dev->base_addr, pcb->length))
-               goto sti_abort;
-
-       for (i = 0; i < pcb->length; i++) {
-               if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
-                       goto sti_abort;
-       }
-
-       outb_control(adapter->hcr_val | 3, dev);        /* signal end of PCB */
-       outb_command(2 + pcb->length, dev->base_addr);
-
-       /* now wait for the acknowledgement */
-       spin_unlock_irqrestore(&adapter->lock, flags);
-
-       for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
-               switch (GET_ASF(dev->base_addr)) {
-               case ASF_PCB_ACK:
-                       adapter->send_pcb_semaphore = 0;
-                       return true;
-
-               case ASF_PCB_NAK:
-#ifdef ELP_DEBUG
-                       pr_debug("%s: send_pcb got NAK\n", dev->name);
-#endif
-                       goto abort;
-               }
-       }
-
-       if (elp_debug >= 1)
-               pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
-                       dev->name, inb_status(dev->base_addr));
-       goto abort;
-
-      sti_abort:
-       spin_unlock_irqrestore(&adapter->lock, flags);
-      abort:
-       adapter->send_pcb_semaphore = 0;
-       return false;
-}
-
-
-/*****************************************************************
- *
- * receive_pcb
- *   Read a PCB from the adapter
- *
- *     wait for ACRF to be non-zero        ---<---+
- *     input a byte                               |
- *     if ASF1 and ASF2 were not both one         |
- *             before byte was read, loop      --->---+
- *     set HSF1 and HSF2 for ack
- *
- *****************************************************************/
-
-static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
-{
-       int i, j;
-       int total_length;
-       int stat;
-       unsigned long timeout;
-       unsigned long flags;
-
-       elp_device *adapter = netdev_priv(dev);
-
-       set_hsf(dev, 0);
-
-       /* get the command code */
-       timeout = jiffies + 2*HZ/100;
-       while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
-       if (time_after_eq(jiffies, timeout)) {
-               TIMEOUT_MSG(__LINE__);
-               return false;
-       }
-       pcb->command = inb_command(dev->base_addr);
-
-       /* read the data length */
-       timeout = jiffies + 3*HZ/100;
-       while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
-       if (time_after_eq(jiffies, timeout)) {
-               TIMEOUT_MSG(__LINE__);
-               pr_info("%s: status %02x\n", dev->name, stat);
-               return false;
-       }
-       pcb->length = inb_command(dev->base_addr);
-
-       if (pcb->length > MAX_PCB_DATA) {
-               INVALID_PCB_MSG(pcb->length);
-               adapter_reset(dev);
-               return false;
-       }
-       /* read the data */
-       spin_lock_irqsave(&adapter->lock, flags);
-       for (i = 0; i < MAX_PCB_DATA; i++) {
-               for (j = 0; j < 20000; j++) {
-                       stat = get_status(dev->base_addr);
-                       if (stat & ACRF)
-                               break;
-               }
-               pcb->data.raw[i] = inb_command(dev->base_addr);
-               if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
-                       break;
-       }
-       spin_unlock_irqrestore(&adapter->lock, flags);
-       if (i >= MAX_PCB_DATA) {
-               INVALID_PCB_MSG(i);
-               return false;
-       }
-       if (j >= 20000) {
-               TIMEOUT_MSG(__LINE__);
-               return false;
-       }
-       /* the last "data" byte was really the length! */
-       total_length = pcb->data.raw[i];
-
-       /* safety check total length vs data length */
-       if (total_length != (pcb->length + 2)) {
-               if (elp_debug >= 2)
-                       pr_warning("%s: mangled PCB received\n", dev->name);
-               set_hsf(dev, HSF_PCB_NAK);
-               return false;
-       }
-
-       if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
-               if (test_and_set_bit(0, (void *) &adapter->busy)) {
-                       if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
-                               set_hsf(dev, HSF_PCB_NAK);
-                               pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
-                               pcb->command = 0;
-                               return true;
-                       } else {
-                               pcb->command = 0xff;
-                       }
-               }
-       }
-       set_hsf(dev, HSF_PCB_ACK);
-       return true;
-}
-
-/******************************************************
- *
- *  queue a receive command on the adapter so we will get an
- *  interrupt when a packet is received.
- *
- ******************************************************/
-
-static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
-{
-       bool status;
-       elp_device *adapter = netdev_priv(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: restarting receiver\n", dev->name);
-       tx_pcb->command = CMD_RECEIVE_PACKET;
-       tx_pcb->length = sizeof(struct Rcv_pkt);
-       tx_pcb->data.rcv_pkt.buf_seg
-           = tx_pcb->data.rcv_pkt.buf_ofs = 0;         /* Unused */
-       tx_pcb->data.rcv_pkt.buf_len = 1600;
-       tx_pcb->data.rcv_pkt.timeout = 0;       /* set timeout to zero */
-       status = send_pcb(dev, tx_pcb);
-       if (status)
-               adapter->rx_active++;
-       return status;
-}
-
-/******************************************************
- *
- * extract a packet from the adapter
- * this routine is only called from within the interrupt
- * service routine, so no cli/sti calls are needed
- * note that the length is always assumed to be even
- *
- ******************************************************/
-
-static void receive_packet(struct net_device *dev, int len)
-{
-       int rlen;
-       elp_device *adapter = netdev_priv(dev);
-       void *target;
-       struct sk_buff *skb;
-       unsigned long flags;
-
-       rlen = (len + 1) & ~1;
-       skb = netdev_alloc_skb(dev, rlen + 2);
-
-       if (!skb) {
-               pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
-               target = adapter->dma_buffer;
-               adapter->current_dma.target = NULL;
-               /* FIXME: stats */
-               return;
-       }
-
-       skb_reserve(skb, 2);
-       target = skb_put(skb, rlen);
-       if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
-               adapter->current_dma.target = target;
-               target = adapter->dma_buffer;
-       } else {
-               adapter->current_dma.target = NULL;
-       }
-
-       /* if this happens, we die */
-       if (test_and_set_bit(0, (void *) &adapter->dmaing))
-               pr_err("%s: rx blocked, DMA in progress, dir %d\n",
-                       dev->name, adapter->current_dma.direction);
-
-       adapter->current_dma.direction = 0;
-       adapter->current_dma.length = rlen;
-       adapter->current_dma.skb = skb;
-       adapter->current_dma.start_time = jiffies;
-
-       outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
-
-       flags=claim_dma_lock();
-       disable_dma(dev->dma);
-       clear_dma_ff(dev->dma);
-       set_dma_mode(dev->dma, 0x04);   /* dma read */
-       set_dma_addr(dev->dma, isa_virt_to_bus(target));
-       set_dma_count(dev->dma, rlen);
-       enable_dma(dev->dma);
-       release_dma_lock(flags);
-
-       if (elp_debug >= 3) {
-               pr_debug("%s: rx DMA transfer started\n", dev->name);
-       }
-
-       if (adapter->rx_active)
-               adapter->rx_active--;
-
-       if (!adapter->busy)
-               pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
-}
-
-/******************************************************
- *
- * interrupt handler
- *
- ******************************************************/
-
-static irqreturn_t elp_interrupt(int irq, void *dev_id)
-{
-       int len;
-       int dlen;
-       int icount = 0;
-       struct net_device *dev = dev_id;
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long timeout;
-
-       spin_lock(&adapter->lock);
-
-       do {
-               /*
-                * has a DMA transfer finished?
-                */
-               if (inb_status(dev->base_addr) & DONE) {
-                       if (!adapter->dmaing)
-                               pr_warning("%s: phantom DMA completed\n", dev->name);
-
-                       if (elp_debug >= 3)
-                               pr_debug("%s: %s DMA complete, status %02x\n", dev->name,
-                                       adapter->current_dma.direction ? "tx" : "rx",
-                                       inb_status(dev->base_addr));
-
-                       outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
-                       if (adapter->current_dma.direction) {
-                               dev_kfree_skb_irq(adapter->current_dma.skb);
-                       } else {
-                               struct sk_buff *skb = adapter->current_dma.skb;
-                               if (skb) {
-                                       if (adapter->current_dma.target) {
-                                       /* have already done the skb_put() */
-                                       memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
-                                       }
-                                       skb->protocol = eth_type_trans(skb,dev);
-                                       dev->stats.rx_bytes += skb->len;
-                                       netif_rx(skb);
-                               }
-                       }
-                       adapter->dmaing = 0;
-                       if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
-                               int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
-                               adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
-                               if (elp_debug >= 2)
-                                       pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
-                               receive_packet(dev, t);
-                       } else {
-                               adapter->busy = 0;
-                       }
-               } else {
-                       /* has one timed out? */
-                       check_3c505_dma(dev);
-               }
-
-               /*
-                * receive a PCB from the adapter
-                */
-               timeout = jiffies + 3*HZ/100;
-               while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
-                       if (receive_pcb(dev, &adapter->irx_pcb)) {
-                               switch (adapter->irx_pcb.command)
-                               {
-                               case 0:
-                                       break;
-                                       /*
-                                        * received a packet - this must be handled fast
-                                        */
-                               case 0xff:
-                               case CMD_RECEIVE_PACKET_COMPLETE:
-                                       /* if the device isn't open, don't pass packets up the stack */
-                                       if (!netif_running(dev))
-                                               break;
-                                       len = adapter->irx_pcb.data.rcv_resp.pkt_len;
-                                       dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
-                                       if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
-                                               pr_err("%s: interrupt - packet not received correctly\n", dev->name);
-                                       } else {
-                                               if (elp_debug >= 3) {
-                                                       pr_debug("%s: interrupt - packet received of length %i (%i)\n",
-                                                               dev->name, len, dlen);
-                                               }
-                                               if (adapter->irx_pcb.command == 0xff) {
-                                                       if (elp_debug >= 2)
-                                                               pr_debug("%s: adding packet to backlog (len = %d)\n",
-                                                                       dev->name, dlen);
-                                                       adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
-                                                       adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
-                                               } else {
-                                                       receive_packet(dev, dlen);
-                                               }
-                                               if (elp_debug >= 3)
-                                                       pr_debug("%s: packet received\n", dev->name);
-                                       }
-                                       break;
-
-                                       /*
-                                        * 82586 configured correctly
-                                        */
-                               case CMD_CONFIGURE_82586_RESPONSE:
-                                       adapter->got[CMD_CONFIGURE_82586] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: interrupt - configure response received\n", dev->name);
-                                       break;
-
-                                       /*
-                                        * Adapter memory configuration
-                                        */
-                               case CMD_CONFIGURE_ADAPTER_RESPONSE:
-                                       adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
-                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-                                       break;
-
-                                       /*
-                                        * Multicast list loading
-                                        */
-                               case CMD_LOAD_MULTICAST_RESPONSE:
-                                       adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: Multicast address list loading %s.\n", dev->name,
-                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-                                       break;
-
-                                       /*
-                                        * Station address setting
-                                        */
-                               case CMD_SET_ADDRESS_RESPONSE:
-                                       adapter->got[CMD_SET_STATION_ADDRESS] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: Ethernet address setting %s.\n", dev->name,
-                                                      adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-                                       break;
-
-
-                                       /*
-                                        * received board statistics
-                                        */
-                               case CMD_NETWORK_STATISTICS_RESPONSE:
-                                       dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
-                                       dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
-                                       dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
-                                       dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
-                                       dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
-                                       dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
-                                       adapter->got[CMD_NETWORK_STATISTICS] = 1;
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: interrupt - statistics response received\n", dev->name);
-                                       break;
-
-                                       /*
-                                        * sent a packet
-                                        */
-                               case CMD_TRANSMIT_PACKET_COMPLETE:
-                                       if (elp_debug >= 3)
-                                               pr_debug("%s: interrupt - packet sent\n", dev->name);
-                                       if (!netif_running(dev))
-                                               break;
-                                       switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
-                                       case 0xffff:
-                                               dev->stats.tx_aborted_errors++;
-                                               pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
-                                               break;
-                                       case 0xfffe:
-                                               dev->stats.tx_fifo_errors++;
-                                               pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
-                                               break;
-                                       }
-                                       netif_wake_queue(dev);
-                                       break;
-
-                                       /*
-                                        * some unknown PCB
-                                        */
-                               default:
-                                       pr_debug("%s: unknown PCB received - %2.2x\n",
-                                               dev->name, adapter->irx_pcb.command);
-                                       break;
-                               }
-                       } else {
-                               pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
-                               adapter_reset(dev);
-                       }
-               }
-
-       } while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
-
-       prime_rx(dev);
-
-       /*
-        * indicate no longer in interrupt routine
-        */
-       spin_unlock(&adapter->lock);
-       return IRQ_HANDLED;
-}
-
-
-/******************************************************
- *
- * open the board
- *
- ******************************************************/
-
-static int elp_open(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       int retval;
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to open device\n", dev->name);
-
-       /*
-        * make sure we actually found the device
-        */
-       if (adapter == NULL) {
-               pr_err("%s: Opening a non-existent physical device\n", dev->name);
-               return -EAGAIN;
-       }
-       /*
-        * disable interrupts on the board
-        */
-       outb_control(0, dev);
-
-       /*
-        * clear any pending interrupts
-        */
-       inb_command(dev->base_addr);
-       adapter_reset(dev);
-
-       /*
-        * no receive PCBs active
-        */
-       adapter->rx_active = 0;
-
-       adapter->busy = 0;
-       adapter->send_pcb_semaphore = 0;
-       adapter->rx_backlog.in = 0;
-       adapter->rx_backlog.out = 0;
-
-       spin_lock_init(&adapter->lock);
-
-       /*
-        * install our interrupt service routine
-        */
-       if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
-               pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
-               return retval;
-       }
-       if ((retval = request_dma(dev->dma, dev->name))) {
-               free_irq(dev->irq, dev);
-               pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
-               return retval;
-       }
-       adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
-       if (!adapter->dma_buffer) {
-               pr_err("%s: could not allocate DMA buffer\n", dev->name);
-               free_dma(dev->dma);
-               free_irq(dev->irq, dev);
-               return -ENOMEM;
-       }
-       adapter->dmaing = 0;
-
-       /*
-        * enable interrupts on the board
-        */
-       outb_control(CMDE, dev);
-
-       /*
-        * configure adapter memory: we need 10 multicast addresses, default==0
-        */
-       if (elp_debug >= 3)
-               pr_debug("%s: sending 3c505 memory configuration command\n", dev->name);
-       adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
-       adapter->tx_pcb.data.memconf.cmd_q = 10;
-       adapter->tx_pcb.data.memconf.rcv_q = 20;
-       adapter->tx_pcb.data.memconf.mcast = 10;
-       adapter->tx_pcb.data.memconf.frame = 20;
-       adapter->tx_pcb.data.memconf.rcv_b = 20;
-       adapter->tx_pcb.data.memconf.progs = 0;
-       adapter->tx_pcb.length = sizeof(struct Memconf);
-       adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-               pr_err("%s: couldn't send memory configuration command\n", dev->name);
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout))
-                       TIMEOUT_MSG(__LINE__);
-       }
-
-
-       /*
-        * configure adapter to receive broadcast messages and wait for response
-        */
-       if (elp_debug >= 3)
-               pr_debug("%s: sending 82586 configure command\n", dev->name);
-       adapter->tx_pcb.command = CMD_CONFIGURE_82586;
-       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
-       adapter->tx_pcb.length = 2;
-       adapter->got[CMD_CONFIGURE_82586] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-               pr_err("%s: couldn't send 82586 configure command\n", dev->name);
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout))
-                       TIMEOUT_MSG(__LINE__);
-       }
-
-       /* enable burst-mode DMA */
-       /* outb(0x1, dev->base_addr + PORT_AUXDMA); */
-
-       /*
-        * queue receive commands to provide buffering
-        */
-       prime_rx(dev);
-       if (elp_debug >= 3)
-               pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
-
-       /*
-        * device is now officially open!
-        */
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-
-/******************************************************
- *
- * send a packet to the adapter
- *
- ******************************************************/
-
-static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
-{
-       elp_device *adapter = netdev_priv(dev);
-       unsigned long target;
-       unsigned long flags;
-
-       /*
-        * make sure the length is even and no shorter than 60 bytes
-        */
-       unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
-
-       if (test_and_set_bit(0, (void *) &adapter->busy)) {
-               if (elp_debug >= 2)
-                       pr_debug("%s: transmit blocked\n", dev->name);
-               return false;
-       }
-
-       dev->stats.tx_bytes += nlen;
-
-       /*
-        * send the adapter a transmit packet command. Ignore segment and offset
-        * and make sure the length is even
-        */
-       adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
-       adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
-       adapter->tx_pcb.data.xmit_pkt.buf_ofs
-           = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0;        /* Unused */
-       adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
-
-       if (!send_pcb(dev, &adapter->tx_pcb)) {
-               adapter->busy = 0;
-               return false;
-       }
-       /* if this happens, we die */
-       if (test_and_set_bit(0, (void *) &adapter->dmaing))
-               pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
-
-       adapter->current_dma.direction = 1;
-       adapter->current_dma.start_time = jiffies;
-
-       if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
-               skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
-               memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
-               target = isa_virt_to_bus(adapter->dma_buffer);
-       }
-       else {
-               target = isa_virt_to_bus(skb->data);
-       }
-       adapter->current_dma.skb = skb;
-
-       flags=claim_dma_lock();
-       disable_dma(dev->dma);
-       clear_dma_ff(dev->dma);
-       set_dma_mode(dev->dma, 0x48);   /* dma memory -> io */
-       set_dma_addr(dev->dma, target);
-       set_dma_count(dev->dma, nlen);
-       outb_control(adapter->hcr_val | DMAE | TCEN, dev);
-       enable_dma(dev->dma);
-       release_dma_lock(flags);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: DMA transfer started\n", dev->name);
-
-       return true;
-}
-
-/*
- *     The upper layer thinks we timed out
- */
-
-static void elp_timeout(struct net_device *dev)
-{
-       int stat;
-
-       stat = inb_status(dev->base_addr);
-       pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
-                  (stat & ACRF) ? "interrupt" : "command");
-       if (elp_debug >= 1)
-               pr_debug("%s: status %#02x\n", dev->name, stat);
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       dev->stats.tx_dropped++;
-       netif_wake_queue(dev);
-}
-
-/******************************************************
- *
- * start the transmitter
- *    return 0 if sent OK, else return 1
- *
- ******************************************************/
-
-static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned long flags;
-       elp_device *adapter = netdev_priv(dev);
-
-       spin_lock_irqsave(&adapter->lock, flags);
-       check_3c505_dma(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
-
-       netif_stop_queue(dev);
-
-       /*
-        * send the packet at skb->data for skb->len
-        */
-       if (!send_packet(dev, skb)) {
-               if (elp_debug >= 2) {
-                       pr_debug("%s: failed to transmit packet\n", dev->name);
-               }
-               spin_unlock_irqrestore(&adapter->lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-       if (elp_debug >= 3)
-               pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
-
-       prime_rx(dev);
-       spin_unlock_irqrestore(&adapter->lock, flags);
-       netif_start_queue(dev);
-       return NETDEV_TX_OK;
-}
-
-/******************************************************
- *
- * return statistics on the board
- *
- ******************************************************/
-
-static struct net_device_stats *elp_get_stats(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request for stats\n", dev->name);
-
-       /* If the device is closed, just return the latest stats we have,
-          - we cannot ask from the adapter without interrupts */
-       if (!netif_running(dev))
-               return &dev->stats;
-
-       /* send a get statistics command to the board */
-       adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
-       adapter->tx_pcb.length = 0;
-       adapter->got[CMD_NETWORK_STATISTICS] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-               pr_err("%s: couldn't send get statistics command\n", dev->name);
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout)) {
-                       TIMEOUT_MSG(__LINE__);
-                       return &dev->stats;
-               }
-       }
-
-       /* statistics are now up to date */
-       return &dev->stats;
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-       return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-       debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-       .get_msglevel           = netdev_get_msglevel,
-       .set_msglevel           = netdev_set_msglevel,
-};
-
-/******************************************************
- *
- * close the board
- *
- ******************************************************/
-
-static int elp_close(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to close device\n", dev->name);
-
-       netif_stop_queue(dev);
-
-       /* Someone may request the device statistic information even when
-        * the interface is closed. The following will update the statistics
-        * structure in the driver, so we'll be able to give current statistics.
-        */
-       (void) elp_get_stats(dev);
-
-       /*
-        * disable interrupts on the board
-        */
-       outb_control(0, dev);
-
-       /*
-        * release the IRQ
-        */
-       free_irq(dev->irq, dev);
-
-       free_dma(dev->dma);
-       free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
-
-       return 0;
-}
-
-
-/************************************************************
- *
- * Set multicast list
- * num_addrs==0: clear mc_list
- * num_addrs==-1: set promiscuous mode
- * num_addrs>0: set mc_list
- *
- ************************************************************/
-
-static void elp_set_mc_list(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       struct netdev_hw_addr *ha;
-       int i;
-       unsigned long flags;
-
-       if (elp_debug >= 3)
-               pr_debug("%s: request to set multicast list\n", dev->name);
-
-       spin_lock_irqsave(&adapter->lock, flags);
-
-       if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
-               /* send a "load multicast list" command to the board, max 10 addrs/cmd */
-               /* if num_addrs==0 the list will be cleared */
-               adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
-               adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
-               i = 0;
-               netdev_for_each_mc_addr(ha, dev)
-                       memcpy(adapter->tx_pcb.data.multicast[i++],
-                              ha->addr, 6);
-               adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
-               if (!send_pcb(dev, &adapter->tx_pcb))
-                       pr_err("%s: couldn't send set_multicast command\n", dev->name);
-               else {
-                       unsigned long timeout = jiffies + TIMEOUT;
-                       while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
-                       if (time_after_eq(jiffies, timeout)) {
-                               TIMEOUT_MSG(__LINE__);
-                       }
-               }
-               if (!netdev_mc_empty(dev))
-                       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
-               else            /* num_addrs == 0 */
-                       adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
-       } else
-               adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
-       /*
-        * configure adapter to receive messages (as specified above)
-        * and wait for response
-        */
-       if (elp_debug >= 3)
-               pr_debug("%s: sending 82586 configure command\n", dev->name);
-       adapter->tx_pcb.command = CMD_CONFIGURE_82586;
-       adapter->tx_pcb.length = 2;
-       adapter->got[CMD_CONFIGURE_82586] = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb))
-       {
-               spin_unlock_irqrestore(&adapter->lock, flags);
-               pr_err("%s: couldn't send 82586 configure command\n", dev->name);
-       }
-       else {
-               unsigned long timeout = jiffies + TIMEOUT;
-               spin_unlock_irqrestore(&adapter->lock, flags);
-               while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
-               if (time_after_eq(jiffies, timeout))
-                       TIMEOUT_MSG(__LINE__);
-       }
-}
-
-/************************************************************
- *
- * A couple of tests to see if there's 3C505 or not
- * Called only by elp_autodetect
- ************************************************************/
-
-static int __init elp_sense(struct net_device *dev)
-{
-       int addr = dev->base_addr;
-       const char *name = dev->name;
-       byte orig_HSR;
-
-       if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
-               return -ENODEV;
-
-       orig_HSR = inb_status(addr);
-
-       if (elp_debug > 0)
-               pr_debug(search_msg, name, addr);
-
-       if (orig_HSR == 0xff) {
-               if (elp_debug > 0)
-                       pr_cont(notfound_msg, 1);
-               goto out;
-       }
-
-       /* Wait for a while; the adapter may still be booting up */
-       if (elp_debug > 0)
-               pr_cont(stilllooking_msg);
-
-       if (orig_HSR & DIR) {
-               /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
-               outb(0, dev->base_addr + PORT_CONTROL);
-               msleep(300);
-               if (inb_status(addr) & DIR) {
-                       if (elp_debug > 0)
-                               pr_cont(notfound_msg, 2);
-                       goto out;
-               }
-       } else {
-               /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
-               outb(DIR, dev->base_addr + PORT_CONTROL);
-               msleep(300);
-               if (!(inb_status(addr) & DIR)) {
-                       if (elp_debug > 0)
-                               pr_cont(notfound_msg, 3);
-                       goto out;
-               }
-       }
-       /*
-        * It certainly looks like a 3c505.
-        */
-       if (elp_debug > 0)
-               pr_cont(found_msg);
-
-       return 0;
-out:
-       release_region(addr, ELP_IO_EXTENT);
-       return -ENODEV;
-}
-
-/*************************************************************
- *
- * Search through addr_list[] and try to find a 3C505
- * Called only by eplus_probe
- *************************************************************/
-
-static int __init elp_autodetect(struct net_device *dev)
-{
-       int idx = 0;
-
-       /* if base address set, then only check that address
-          otherwise, run through the table */
-       if (dev->base_addr != 0) {      /* dev->base_addr == 0 ==> plain autodetect */
-               if (elp_sense(dev) == 0)
-                       return dev->base_addr;
-       } else
-               while ((dev->base_addr = addr_list[idx++])) {
-                       if (elp_sense(dev) == 0)
-                               return dev->base_addr;
-               }
-
-       /* could not find an adapter */
-       if (elp_debug > 0)
-               pr_debug(couldnot_msg, dev->name);
-
-       return 0;               /* Because of this, the layer above will return -ENODEV */
-}
-
-static const struct net_device_ops elp_netdev_ops = {
-       .ndo_open               = elp_open,
-       .ndo_stop               = elp_close,
-       .ndo_get_stats          = elp_get_stats,
-       .ndo_start_xmit         = elp_start_xmit,
-       .ndo_tx_timeout         = elp_timeout,
-       .ndo_set_rx_mode        = elp_set_mc_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/******************************************************
- *
- * probe for an Etherlink Plus board at the specified address
- *
- ******************************************************/
-
-/* There are three situations we need to be able to detect here:
-
- *  a) the card is idle
- *  b) the card is still booting up
- *  c) the card is stuck in a strange state (some DOS drivers do this)
- *
- * In case (a), all is well.  In case (b), we wait 10 seconds to see if the
- * card finishes booting, and carry on if so.  In case (c), we do a hard reset,
- * loop round, and hope for the best.
- *
- * This is all very unpleasant, but hopefully avoids the problems with the old
- * probe code (which had a 15-second delay if the card was idle, and didn't
- * work at all if it was in a weird state).
- */
-
-static int __init elplus_setup(struct net_device *dev)
-{
-       elp_device *adapter = netdev_priv(dev);
-       int i, tries, tries1, okay;
-       unsigned long timeout;
-       unsigned long cookie = 0;
-       int err = -ENODEV;
-
-       /*
-        *  setup adapter structure
-        */
-
-       dev->base_addr = elp_autodetect(dev);
-       if (!dev->base_addr)
-               return -ENODEV;
-
-       adapter->send_pcb_semaphore = 0;
-
-       for (tries1 = 0; tries1 < 3; tries1++) {
-               outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
-               /* First try to write just one byte, to see if the card is
-                * responding at all normally.
-                */
-               timeout = jiffies + 5*HZ/100;
-               okay = 0;
-               while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
-               if ((inb_status(dev->base_addr) & HCRE)) {
-                       outb_command(0, dev->base_addr);        /* send a spurious byte */
-                       timeout = jiffies + 5*HZ/100;
-                       while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
-                       if (inb_status(dev->base_addr) & HCRE)
-                               okay = 1;
-               }
-               if (!okay) {
-                       /* Nope, it's ignoring the command register.  This means that
-                        * either it's still booting up, or it's died.
-                        */
-                       pr_err("%s: command register wouldn't drain, ", dev->name);
-                       if ((inb_status(dev->base_addr) & 7) == 3) {
-                               /* If the adapter status is 3, it *could* still be booting.
-                                * Give it the benefit of the doubt for 10 seconds.
-                                */
-                               pr_cont("assuming 3c505 still starting\n");
-                               timeout = jiffies + 10*HZ;
-                               while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
-                               if (inb_status(dev->base_addr) & 7) {
-                                       pr_err("%s: 3c505 failed to start\n", dev->name);
-                               } else {
-                                       okay = 1;  /* It started */
-                               }
-                       } else {
-                               /* Otherwise, it must just be in a strange
-                                * state.  We probably need to kick it.
-                                */
-                               pr_cont("3c505 is sulking\n");
-                       }
-               }
-               for (tries = 0; tries < 5 && okay; tries++) {
-
-                       /*
-                        * Try to set the Ethernet address, to make sure that the board
-                        * is working.
-                        */
-                       adapter->tx_pcb.command = CMD_STATION_ADDRESS;
-                       adapter->tx_pcb.length = 0;
-                       cookie = probe_irq_on();
-                       if (!send_pcb(dev, &adapter->tx_pcb)) {
-                               pr_err("%s: could not send first PCB\n", dev->name);
-                               probe_irq_off(cookie);
-                               continue;
-                       }
-                       if (!receive_pcb(dev, &adapter->rx_pcb)) {
-                               pr_err("%s: could not read first PCB\n", dev->name);
-                               probe_irq_off(cookie);
-                               continue;
-                       }
-                       if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
-                           (adapter->rx_pcb.length != 6)) {
-                               pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
-                                       adapter->rx_pcb.command, adapter->rx_pcb.length);
-                               probe_irq_off(cookie);
-                               continue;
-                       }
-                       goto okay;
-               }
-               /* It's broken.  Do a hard reset to re-initialise the board,
-                * and try again.
-                */
-               pr_info("%s: resetting adapter\n", dev->name);
-               outb_control(adapter->hcr_val | FLSH | ATTN, dev);
-               outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
-       }
-       pr_err("%s: failed to initialise 3c505\n", dev->name);
-       goto out;
-
-      okay:
-       if (dev->irq) {         /* Is there a preset IRQ? */
-               int rpt = probe_irq_off(cookie);
-               if (dev->irq != rpt) {
-                       pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
-               }
-               /* if dev->irq == probe_irq_off(cookie), all is well */
-       } else                 /* No preset IRQ; just use what we can detect */
-               dev->irq = probe_irq_off(cookie);
-       switch (dev->irq) {    /* Legal, sane? */
-       case 0:
-               pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
-                      dev->name);
-               goto out;
-       case 1:
-       case 6:
-       case 8:
-       case 13:
-               pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
-                      dev->name, dev->irq);
-                      goto out;
-       }
-       /*
-        *  Now we have the IRQ number so we can disable the interrupts from
-        *  the board until the board is opened.
-        */
-       outb_control(adapter->hcr_val & ~CMDE, dev);
-
-       /*
-        * copy Ethernet address into structure
-        */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
-
-       /* find a DMA channel */
-       if (!dev->dma) {
-               if (dev->mem_start) {
-                       dev->dma = dev->mem_start & 7;
-               }
-               else {
-                       pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
-                       dev->dma = ELP_DMA;
-               }
-       }
-
-       /*
-        * print remainder of startup message
-        */
-       pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
-               dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
-       /*
-        * read more information from the adapter
-        */
-
-       adapter->tx_pcb.command = CMD_ADAPTER_INFO;
-       adapter->tx_pcb.length = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb) ||
-           !receive_pcb(dev, &adapter->rx_pcb) ||
-           (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
-           (adapter->rx_pcb.length != 10)) {
-               pr_cont("not responding to second PCB\n");
-       }
-       pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
-               adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
-
-       /*
-        * reconfigure the adapter memory to better suit our purposes
-        */
-       adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
-       adapter->tx_pcb.length = 12;
-       adapter->tx_pcb.data.memconf.cmd_q = 8;
-       adapter->tx_pcb.data.memconf.rcv_q = 8;
-       adapter->tx_pcb.data.memconf.mcast = 10;
-       adapter->tx_pcb.data.memconf.frame = 10;
-       adapter->tx_pcb.data.memconf.rcv_b = 10;
-       adapter->tx_pcb.data.memconf.progs = 0;
-       if (!send_pcb(dev, &adapter->tx_pcb) ||
-           !receive_pcb(dev, &adapter->rx_pcb) ||
-           (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
-           (adapter->rx_pcb.length != 2)) {
-               pr_err("%s: could not configure adapter memory\n", dev->name);
-       }
-       if (adapter->rx_pcb.data.configure) {
-               pr_err("%s: adapter configuration failed\n", dev->name);
-       }
-
-       dev->netdev_ops = &elp_netdev_ops;
-       dev->watchdog_timeo = 10*HZ;
-       dev->ethtool_ops = &netdev_ethtool_ops;         /* local */
-
-       dev->mem_start = dev->mem_end = 0;
-
-       err = register_netdev(dev);
-       if (err)
-               goto out;
-
-       return 0;
-out:
-       release_region(dev->base_addr, ELP_IO_EXTENT);
-       return err;
-}
-
-#ifndef MODULE
-struct net_device * __init elplus_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(elp_device));
-       int err;
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = elplus_setup(dev);
-       if (err) {
-               free_netdev(dev);
-               return ERR_PTR(err);
-       }
-       return dev;
-}
-
-#else
-static struct net_device *dev_3c505[ELP_MAX_CARDS];
-static int io[ELP_MAX_CARDS];
-static int irq[ELP_MAX_CARDS];
-static int dma[ELP_MAX_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(dma, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
-MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
-
-int __init init_module(void)
-{
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
-               struct net_device *dev = alloc_etherdev(sizeof(elp_device));
-               if (!dev)
-                       break;
-
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               if (dma[this_dev]) {
-                       dev->dma = dma[this_dev];
-               } else {
-                       dev->dma = ELP_DMA;
-                       pr_warning("3c505.c: warning, using default DMA channel,\n");
-               }
-               if (io[this_dev] == 0) {
-                       if (this_dev) {
-                               free_netdev(dev);
-                               break;
-                       }
-                       pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
-               }
-               if (elplus_setup(dev) != 0) {
-                       pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
-                       free_netdev(dev);
-                       break;
-               }
-               dev_3c505[this_dev] = dev;
-               found++;
-       }
-       if (!found)
-               return -ENODEV;
-       return 0;
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
-               struct net_device *dev = dev_3c505[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       release_region(dev->base_addr, ELP_IO_EXTENT);
-                       free_netdev(dev);
-               }
-       }
-}
-
-#endif                         /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/3c505.h b/drivers/net/ethernet/i825xx/3c505.h
deleted file mode 100644 (file)
index 04df2a9..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*****************************************************************
- *
- *  defines for 3Com Etherlink Plus adapter
- *
- *****************************************************************/
-
-#define ELP_DMA       6
-#define ELP_RX_PCBS   4
-#define ELP_MAX_CARDS 4
-
-/*
- * I/O register offsets
- */
-#define        PORT_COMMAND    0x00    /* read/write, 8-bit */
-#define        PORT_STATUS     0x02    /* read only, 8-bit */
-#define        PORT_AUXDMA     0x02    /* write only, 8-bit */
-#define        PORT_DATA       0x04    /* read/write, 16-bit */
-#define        PORT_CONTROL    0x06    /* read/write, 8-bit */
-
-#define ELP_IO_EXTENT  0x10    /* size of used IO registers */
-
-/*
- * host control registers bits
- */
-#define        ATTN    0x80    /* attention */
-#define        FLSH    0x40    /* flush data register */
-#define DMAE   0x20    /* DMA enable */
-#define DIR    0x10    /* direction */
-#define        TCEN    0x08    /* terminal count interrupt enable */
-#define        CMDE    0x04    /* command register interrupt enable */
-#define        HSF2    0x02    /* host status flag 2 */
-#define        HSF1    0x01    /* host status flag 1 */
-
-/*
- * combinations of HSF flags used for PCB transmission
- */
-#define        HSF_PCB_ACK     HSF1
-#define        HSF_PCB_NAK     HSF2
-#define        HSF_PCB_END     (HSF2|HSF1)
-#define        HSF_PCB_MASK    (HSF2|HSF1)
-
-/*
- * host status register bits
- */
-#define        HRDY    0x80    /* data register ready */
-#define        HCRE    0x40    /* command register empty */
-#define        ACRF    0x20    /* adapter command register full */
-/* #define DIR         0x10    direction - same as in control register */
-#define        DONE    0x08    /* DMA done */
-#define        ASF3    0x04    /* adapter status flag 3 */
-#define        ASF2    0x02    /* adapter status flag 2 */
-#define        ASF1    0x01    /* adapter status flag 1 */
-
-/*
- * combinations of ASF flags used for PCB reception
- */
-#define        ASF_PCB_ACK     ASF1
-#define        ASF_PCB_NAK     ASF2
-#define        ASF_PCB_END     (ASF2|ASF1)
-#define        ASF_PCB_MASK    (ASF2|ASF1)
-
-/*
- * host aux DMA register bits
- */
-#define        DMA_BRST        0x01    /* DMA burst */
-
-/*
- * maximum amount of data allowed in a PCB
- */
-#define        MAX_PCB_DATA    62
-
-/*****************************************************************
- *
- *  timeout value
- *     this is a rough value used for loops to stop them from
- *     locking up the whole machine in the case of failure or
- *     error conditions
- *
- *****************************************************************/
-
-#define        TIMEOUT 300
-
-/*****************************************************************
- *
- * PCB commands
- *
- *****************************************************************/
-
-enum {
-  /*
-   * host PCB commands
-   */
-  CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
-  CMD_CONFIGURE_82586          = 0x02,
-  CMD_STATION_ADDRESS          = 0x03,
-  CMD_DMA_DOWNLOAD             = 0x04,
-  CMD_DMA_UPLOAD               = 0x05,
-  CMD_PIO_DOWNLOAD             = 0x06,
-  CMD_PIO_UPLOAD               = 0x07,
-  CMD_RECEIVE_PACKET           = 0x08,
-  CMD_TRANSMIT_PACKET          = 0x09,
-  CMD_NETWORK_STATISTICS       = 0x0a,
-  CMD_LOAD_MULTICAST_LIST      = 0x0b,
-  CMD_CLEAR_PROGRAM            = 0x0c,
-  CMD_DOWNLOAD_PROGRAM         = 0x0d,
-  CMD_EXECUTE_PROGRAM          = 0x0e,
-  CMD_SELF_TEST                        = 0x0f,
-  CMD_SET_STATION_ADDRESS      = 0x10,
-  CMD_ADAPTER_INFO             = 0x11,
-  NUM_TRANSMIT_CMDS,
-
-  /*
-   * adapter PCB commands
-   */
-  CMD_CONFIGURE_ADAPTER_RESPONSE       = 0x31,
-  CMD_CONFIGURE_82586_RESPONSE         = 0x32,
-  CMD_ADDRESS_RESPONSE                 = 0x33,
-  CMD_DOWNLOAD_DATA_REQUEST            = 0x34,
-  CMD_UPLOAD_DATA_REQUEST              = 0x35,
-  CMD_RECEIVE_PACKET_COMPLETE          = 0x38,
-  CMD_TRANSMIT_PACKET_COMPLETE         = 0x39,
-  CMD_NETWORK_STATISTICS_RESPONSE      = 0x3a,
-  CMD_LOAD_MULTICAST_RESPONSE          = 0x3b,
-  CMD_CLEAR_PROGRAM_RESPONSE           = 0x3c,
-  CMD_DOWNLOAD_PROGRAM_RESPONSE                = 0x3d,
-  CMD_EXECUTE_RESPONSE                 = 0x3e,
-  CMD_SELF_TEST_RESPONSE               = 0x3f,
-  CMD_SET_ADDRESS_RESPONSE             = 0x40,
-  CMD_ADAPTER_INFO_RESPONSE            = 0x41
-};
-
-/* Definitions for the PCB data structure */
-
-/* Data units */
-typedef unsigned char         byte;
-typedef unsigned short int    word;
-typedef unsigned long int     dword;
-
-/* Data structures */
-struct Memconf {
-       word    cmd_q,
-               rcv_q,
-               mcast,
-               frame,
-               rcv_b,
-               progs;
-};
-
-struct Rcv_pkt {
-       word    buf_ofs,
-               buf_seg,
-               buf_len,
-               timeout;
-};
-
-struct Xmit_pkt {
-       word    buf_ofs,
-               buf_seg,
-               pkt_len;
-};
-
-struct Rcv_resp {
-       word    buf_ofs,
-               buf_seg,
-               buf_len,
-               pkt_len,
-               timeout,
-               status;
-       dword   timetag;
-};
-
-struct Xmit_resp {
-       word    buf_ofs,
-               buf_seg,
-               c_stat,
-               status;
-};
-
-
-struct Netstat {
-       dword   tot_recv,
-               tot_xmit;
-       word    err_CRC,
-               err_align,
-               err_res,
-               err_ovrrun;
-};
-
-
-struct Selftest {
-       word    error;
-       union {
-               word ROM_cksum;
-               struct {
-                       word ofs, seg;
-               } RAM;
-               word i82586;
-       } failure;
-};
-
-struct Info {
-       byte    minor_vers,
-               major_vers;
-       word    ROM_cksum,
-               RAM_sz,
-               free_ofs,
-               free_seg;
-};
-
-struct Memdump {
-       word size,
-            off,
-            seg;
-};
-
-/*
-Primary Command Block. The most important data structure. All communication
-between the host and the adapter is done with these. (Except for the actual
-Ethernet data, which has different packaging.)
-*/
-typedef struct {
-       byte    command;
-       byte    length;
-       union   {
-               struct Memconf          memconf;
-               word                    configure;
-               struct Rcv_pkt          rcv_pkt;
-               struct Xmit_pkt         xmit_pkt;
-               byte                    multicast[10][6];
-               byte                    eth_addr[6];
-               byte                    failed;
-               struct Rcv_resp         rcv_resp;
-               struct Xmit_resp        xmit_resp;
-               struct Netstat          netstat;
-               struct Selftest         selftest;
-               struct Info             info;
-               struct Memdump          memdump;
-               byte                    raw[62];
-       } data;
-} pcb_struct;
-
-/* These defines for 'configure' */
-#define RECV_STATION   0x00
-#define RECV_BROAD     0x01
-#define RECV_MULTI     0x02
-#define RECV_PROMISC   0x04
-#define NO_LOOPBACK    0x00
-#define INT_LOOPBACK   0x08
-#define EXT_LOOPBACK   0x10
-
-/*****************************************************************
- *
- *  structure to hold context information for adapter
- *
- *****************************************************************/
-
-#define DMA_BUFFER_SIZE  1600
-#define BACKLOG_SIZE      4
-
-typedef struct {
-       volatile short got[NUM_TRANSMIT_CMDS];  /* flags for
-                                                  command completion */
-       pcb_struct tx_pcb;      /* PCB for foreground sending */
-       pcb_struct rx_pcb;      /* PCB for foreground receiving */
-       pcb_struct itx_pcb;     /* PCB for background sending */
-       pcb_struct irx_pcb;     /* PCB for background receiving */
-
-       void *dma_buffer;
-
-       struct {
-               unsigned int length[BACKLOG_SIZE];
-               unsigned int in;
-               unsigned int out;
-       } rx_backlog;
-
-       struct {
-               unsigned int direction;
-               unsigned int length;
-               struct sk_buff *skb;
-               void *target;
-               unsigned long start_time;
-       } current_dma;
-
-       /* flags */
-       unsigned long send_pcb_semaphore;
-       unsigned long dmaing;
-       unsigned long busy;
-
-       unsigned int rx_active;  /* number of receive PCBs */
-        volatile unsigned char hcr_val;  /* what we think the HCR contains */
-        spinlock_t lock;       /* Interrupt v tx lock */
-} elp_device;
diff --git a/drivers/net/ethernet/i825xx/3c507.c b/drivers/net/ethernet/i825xx/3c507.c
deleted file mode 100644 (file)
index e8984b0..0000000
+++ /dev/null
@@ -1,938 +0,0 @@
-/* 3c507.c: An EtherLink16 device driver for Linux. */
-/*
-       Written 1993,1994 by Donald Becker.
-
-       Copyright 1993 United States Government as represented by the
-       Director, National Security Agency.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-
-       Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
-       and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
-       Mark Salazar <leslie@access.digex.net> made the changes for cards with
-       only 16K packet buffers.
-
-       Things remaining to do:
-       Verify that the tx and rx buffers don't have fencepost errors.
-       Move the theory of operation and memory map documentation.
-       The statistics need to be updated correctly.
-*/
-
-#define DRV_NAME               "3c507"
-#define DRV_VERSION            "1.10a"
-#define DRV_RELDATE            "11/17/2001"
-
-static const char version[] =
-       DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
-
-/*
-  Sources:
-       This driver wouldn't have been written with the availability of the
-       Crynwr driver source code.      It provided a known-working implementation
-       that filled in the gaping holes of the Intel documentation.  Three cheers
-       for Russ Nelson.
-
-       Intel Microcommunications Databook, Vol. 1, 1990.  It provides just enough
-       info that the casual reader might think that it documents the i82586 :-<.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-/* use 0 for production, 1 for verification, 2..7 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-#define debug net_debug
-
-
-/*
-                       Details of the i82586.
-
-   You'll really need the databook to understand the details of this part,
-   but the outline is that the i82586 has two separate processing units.
-   Both are started from a list of three configuration tables, of which only
-   the last, the System Control Block (SCB), is used after reset-time.  The SCB
-   has the following fields:
-               Status word
-               Command word
-               Tx/Command block addr.
-               Rx block addr.
-   The command word accepts the following controls for the Tx and Rx units:
-  */
-
-#define         CUC_START       0x0100
-#define         CUC_RESUME      0x0200
-#define         CUC_SUSPEND 0x0300
-#define         RX_START        0x0010
-#define         RX_RESUME       0x0020
-#define         RX_SUSPEND      0x0030
-
-/* The Rx unit uses a list of frame descriptors and a list of data buffer
-   descriptors.  We use full-sized (1518 byte) data buffers, so there is
-   a one-to-one pairing of frame descriptors to buffer descriptors.
-
-   The Tx ("command") unit executes a list of commands that look like:
-               Status word             Written by the 82586 when the command is done.
-               Command word    Command in lower 3 bits, post-command action in upper 3
-               Link word               The address of the next command.
-               Parameters              (as needed).
-
-       Some definitions related to the Command Word are:
- */
-#define CMD_EOL                0x8000                  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000                  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000                  /* Interrupt after doing cmd. */
-
-enum commands {
-       CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-       CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-/* Information that need to be kept for each board. */
-struct net_local {
-       int last_restart;
-       ushort rx_head;
-       ushort rx_tail;
-       ushort tx_head;
-       ushort tx_cmd_link;
-       ushort tx_reap;
-       ushort tx_pkts_in_ring;
-       spinlock_t lock;
-       void __iomem *base;
-};
-
-/*
-               Details of the EtherLink16 Implementation
-  The 3c507 is a generic shared-memory i82586 implementation.
-  The host can map 16K, 32K, 48K, or 64K of the 64K memory into
-  0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
-  */
-
-/* Offsets from the base I/O address. */
-#define        SA_DATA         0       /* Station address data, or 3Com signature. */
-#define MISC_CTRL      6       /* Switch the SA_DATA banks, and bus config bits. */
-#define RESET_IRQ      10      /* Reset the latched IRQ line. */
-#define SIGNAL_CA      11      /* Frob the 82586 Channel Attention line. */
-#define ROM_CONFIG     13
-#define MEM_CONFIG     14
-#define IRQ_CONFIG     15
-#define EL16_IO_EXTENT 16
-
-/* The ID port is used at boot-time to locate the ethercard. */
-#define ID_PORT                0x100
-
-/* Offsets to registers in the mailbox (SCB). */
-#define iSCB_STATUS    0x8
-#define iSCB_CMD               0xA
-#define iSCB_CBL               0xC     /* Command BLock offset. */
-#define iSCB_RFA               0xE     /* Rx Frame Area offset. */
-
-/*  Since the 3c507 maps the shared memory window so that the last byte is
-       at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
-       48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
-       We can account for this be setting the 'SBC Base' entry in the ISCP table
-       below for all the 16 bit offset addresses, and also adding the 'SCB Base'
-       value to all 24 bit physical addresses (in the SCP table and the TX and RX
-       Buffer Descriptors).
-                                       -Mark
-       */
-#define SCB_BASE               ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
-
-/*
-  What follows in 'init_words[]' is the "program" that is downloaded to the
-  82586 memory.         It's mostly tables and command blocks, and starts at the
-  reset address 0xfffff6.  This is designed to be similar to the EtherExpress,
-  thus the unusual location of the SCB at 0x0008.
-
-  Even with the additional "don't care" values, doing it this way takes less
-  program space than initializing the individual tables, and I feel it's much
-  cleaner.
-
-  The databook is particularly useless for the first two structures, I had
-  to use the Crynwr driver as an example.
-
-   The memory setup is as follows:
-   */
-
-#define CONFIG_CMD     0x0018
-#define SET_SA_CMD     0x0024
-#define SA_OFFSET      0x002A
-#define IDLELOOP       0x30
-#define TDR_CMD                0x38
-#define TDR_TIME       0x3C
-#define DUMP_CMD       0x40
-#define DIAG_CMD       0x48
-#define SET_MC_CMD     0x4E
-#define DUMP_DATA      0x56    /* A 170 byte buffer for dump and Set-MC into. */
-
-#define TX_BUF_START   0x0100
-#define NUM_TX_BUFS    5
-#define TX_BUF_SIZE    (1518+14+20+16) /* packet+header+TBD */
-
-#define RX_BUF_START   0x2000
-#define RX_BUF_SIZE    (1518+14+18)    /* packet+header+RBD */
-#define RX_BUF_END             (dev->mem_end - dev->mem_start)
-
-#define TX_TIMEOUT (HZ/20)
-
-/*
-  That's it: only 86 bytes to set up the beast, including every extra
-  command available.  The 170 byte buffer at DUMP_DATA is shared between the
-  Dump command (called only by the diagnostic program) and the SetMulticastList
-  command.
-
-  To complete the memory setup you only have to write the station address at
-  SA_OFFSET and create the Tx & Rx buffer lists.
-
-  The Tx command chain and buffer list is setup as follows:
-  A Tx command table, with the data buffer pointing to...
-  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
-       chaining together several smaller buffers.
-  A NoOp command, which initially points to itself,
-  And the packet data.
-
-  A transmit is done by filling in the Tx command table and data buffer,
-  re-writing the NoOp command, and finally changing the offset of the last
-  command to point to the current Tx command.  When the Tx command is finished,
-  it jumps to the NoOp, when it loops until the next Tx command changes the
-  "link offset" in the NoOp.  This way the 82586 never has to go through the
-  slow restart sequence.
-
-  The Rx buffer list is set up in the obvious ring structure.  We have enough
-  memory (and low enough interrupt latency) that we can avoid the complicated
-  Rx buffer linked lists by alway associating a full-size Rx data buffer with
-  each Rx data frame.
-
-  I current use four transmit buffers starting at TX_BUF_START (0x0100), and
-  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
-
-  */
-
-static unsigned short init_words[] = {
-       /*      System Configuration Pointer (SCP). */
-       0x0000,                                 /* Set bus size to 16 bits. */
-       0,0,                                    /* pad words. */
-       0x0000,0x0000,                  /* ISCP phys addr, set in init_82586_mem(). */
-
-       /*      Intermediate System Configuration Pointer (ISCP). */
-       0x0001,                                 /* Status word that's cleared when init is done. */
-       0x0008,0,0,                             /* SCB offset, (skip, skip) */
-
-       /* System Control Block (SCB). */
-       0,0xf000|RX_START|CUC_START,    /* SCB status and cmd. */
-       CONFIG_CMD,                             /* Command list pointer, points to Configure. */
-       RX_BUF_START,                           /* Rx block list. */
-       0,0,0,0,                                /* Error count: CRC, align, buffer, overrun. */
-
-       /* 0x0018: Configure command.  Change to put MAC data with packet. */
-       0, CmdConfigure,                /* Status, command.             */
-       SET_SA_CMD,                             /* Next command is Set Station Addr. */
-       0x0804,                                 /* "4" bytes of config data, 8 byte FIFO. */
-       0x2e40,                                 /* Magic values, including MAC data location. */
-       0,                                              /* Unused pad word. */
-
-       /* 0x0024: Setup station address command. */
-       0, CmdSASetup,
-       SET_MC_CMD,                             /* Next command. */
-       0xaa00,0xb000,0x0bad,   /* Station address (to be filled in) */
-
-       /* 0x0030: NOP, looping back to itself.  Point to first Tx buffer to Tx. */
-       0, CmdNOp, IDLELOOP, 0 /* pad */,
-
-       /* 0x0038: A unused Time-Domain Reflectometer command. */
-       0, CmdTDR, IDLELOOP, 0,
-
-       /* 0x0040: An unused Dump State command. */
-       0, CmdDump, IDLELOOP, DUMP_DATA,
-
-       /* 0x0048: An unused Diagnose command. */
-       0, CmdDiagnose, IDLELOOP,
-
-       /* 0x004E: An empty set-multicast-list command. */
-       0, CmdMulticastList, IDLELOOP, 0,
-};
-
-/* Index to functions, as function prototypes. */
-
-static int     el16_probe1(struct net_device *dev, int ioaddr);
-static int     el16_open(struct net_device *dev);
-static netdev_tx_t el16_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev);
-static irqreturn_t el16_interrupt(int irq, void *dev_id);
-static void el16_rx(struct net_device *dev);
-static int     el16_close(struct net_device *dev);
-static void el16_tx_timeout (struct net_device *dev);
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
-static void init_82586_mem(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-static void init_rx_bufs(struct net_device *);
-
-static int io = 0x300;
-static int irq;
-static int mem_start;
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-       If dev->base_addr == 0, probe all likely locations.
-       If dev->base_addr == 1, always return failure.
-       If dev->base_addr == 2, (detachable devices only) allocate space for the
-       device and return success.
-       */
-
-struct net_device * __init el16_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-       static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
-       const unsigned *port;
-       int err = -ENODEV;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-               mem_start = dev->mem_start & 15;
-       }
-
-       if (io > 0x1ff)         /* Check a single specified location. */
-               err = el16_probe1(dev, io);
-       else if (io != 0)
-               err = -ENXIO;           /* Don't probe at all. */
-       else {
-               for (port = ports; *port; port++) {
-                       err = el16_probe1(dev, *port);
-                       if (!err)
-                               break;
-               }
-       }
-
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       free_irq(dev->irq, dev);
-       iounmap(((struct net_local *)netdev_priv(dev))->base);
-       release_region(dev->base_addr, EL16_IO_EXTENT);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops netdev_ops = {
-       .ndo_open               = el16_open,
-       .ndo_stop               = el16_close,
-       .ndo_start_xmit         = el16_send_packet,
-       .ndo_tx_timeout         = el16_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init el16_probe1(struct net_device *dev, int ioaddr)
-{
-       static unsigned char init_ID_done;
-       int i, irq, irqval, retval;
-       struct net_local *lp;
-
-       if (init_ID_done == 0) {
-               ushort lrs_state = 0xff;
-               /* Send the ID sequence to the ID_PORT to enable the board(s). */
-               outb(0x00, ID_PORT);
-               for(i = 0; i < 255; i++) {
-                       outb(lrs_state, ID_PORT);
-                       lrs_state <<= 1;
-                       if (lrs_state & 0x100)
-                               lrs_state ^= 0xe7;
-               }
-               outb(0x00, ID_PORT);
-               init_ID_done = 1;
-       }
-
-       if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
-               return -ENODEV;
-
-       if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
-           (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
-
-       /* We should make a few more checks here, like the first three octets of
-          the S.A. for the manufacturer's code. */
-
-       irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
-       irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
-       if (irqval) {
-               pr_cont("\n");
-               pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
-               retval = -EAGAIN;
-               goto out;
-       }
-
-       /* We've committed to using the board, and can start filling in *dev. */
-       dev->base_addr = ioaddr;
-
-       outb(0x01, ioaddr + MISC_CTRL);
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = inb(ioaddr + i);
-       pr_cont(" %pM", dev->dev_addr);
-
-       if (mem_start)
-               net_debug = mem_start & 7;
-
-#ifdef MEM_BASE
-       dev->mem_start = MEM_BASE;
-       dev->mem_end = dev->mem_start + 0x10000;
-#else
-       {
-               int base;
-               int size;
-               char mem_config = inb(ioaddr + MEM_CONFIG);
-               if (mem_config & 0x20) {
-                       size = 64*1024;
-                       base = 0xf00000 + (mem_config & 0x08 ? 0x080000
-                                                          : ((mem_config & 3) << 17));
-               } else {
-                       size = ((mem_config & 3) + 1) << 14;
-                       base = 0x0c0000 + ( (mem_config & 0x18) << 12);
-               }
-               dev->mem_start = base;
-               dev->mem_end = base + size;
-       }
-#endif
-
-       dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
-       dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
-       pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
-                  dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
-
-       if (net_debug)
-               pr_debug("%s", version);
-
-       lp = netdev_priv(dev);
-       spin_lock_init(&lp->lock);
-       lp->base = ioremap(dev->mem_start, RX_BUF_END);
-       if (!lp->base) {
-               pr_err("3c507: unable to remap memory\n");
-               retval = -EAGAIN;
-               goto out1;
-       }
-
-       dev->netdev_ops = &netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-       dev->ethtool_ops = &netdev_ethtool_ops;
-       dev->flags &= ~IFF_MULTICAST;   /* Multicast doesn't work */
-       return 0;
-out1:
-       free_irq(dev->irq, dev);
-out:
-       release_region(ioaddr, EL16_IO_EXTENT);
-       return retval;
-}
-
-static int el16_open(struct net_device *dev)
-{
-       /* Initialize the 82586 memory and start it. */
-       init_82586_mem(dev);
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-
-static void el16_tx_timeout (struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       void __iomem *shmem = lp->base;
-
-       if (net_debug > 1)
-               pr_debug("%s: transmit timed out, %s?  ", dev->name,
-                       readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
-                       "network cable problem");
-       /* Try to restart the adaptor. */
-       if (lp->last_restart == dev->stats.tx_packets) {
-               if (net_debug > 1)
-                       pr_cont("Resetting board.\n");
-               /* Completely reset the adaptor. */
-               init_82586_mem (dev);
-               lp->tx_pkts_in_ring = 0;
-       } else {
-               /* Issue the channel attention signal and hope it "gets better". */
-               if (net_debug > 1)
-                       pr_cont("Kicking board.\n");
-               writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
-               outb (0, ioaddr + SIGNAL_CA);   /* Issue channel-attn. */
-               lp->last_restart = dev->stats.tx_packets;
-       }
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue (dev);
-}
-
-
-static netdev_tx_t el16_send_packet (struct sk_buff *skb,
-                                    struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned long flags;
-       short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-       unsigned char *buf = skb->data;
-
-       netif_stop_queue (dev);
-
-       spin_lock_irqsave (&lp->lock, flags);
-
-       dev->stats.tx_bytes += length;
-       /* Disable the 82586's input to the interrupt line. */
-       outb (0x80, ioaddr + MISC_CTRL);
-
-       hardware_send_packet (dev, buf, skb->len, length - skb->len);
-
-       /* Enable the 82586 interrupt input. */
-       outb (0x84, ioaddr + MISC_CTRL);
-
-       spin_unlock_irqrestore (&lp->lock, flags);
-
-       dev_kfree_skb (skb);
-
-       /* You might need to clean up and record Tx statistics here. */
-
-       return NETDEV_TX_OK;
-}
-
-/*     The typical workload of the driver:
-       Handle the network interface interrupts. */
-static irqreturn_t el16_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct net_local *lp;
-       int ioaddr, status, boguscount = 0;
-       ushort ack_cmd = 0;
-       void __iomem *shmem;
-
-       if (dev == NULL) {
-               pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
-               return IRQ_NONE;
-       }
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-       shmem = lp->base;
-
-       spin_lock(&lp->lock);
-
-       status = readw(shmem+iSCB_STATUS);
-
-       if (net_debug > 4) {
-               pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
-       }
-
-       /* Disable the 82586's input to the interrupt line. */
-       outb(0x80, ioaddr + MISC_CTRL);
-
-       /* Reap the Tx packet buffers. */
-       while (lp->tx_pkts_in_ring) {
-         unsigned short tx_status = readw(shmem+lp->tx_reap);
-         if (!(tx_status & 0x8000)) {
-               if (net_debug > 5)
-                       pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
-               break;
-         }
-         /* Tx unsuccessful or some interesting status bit set. */
-         if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
-               dev->stats.tx_errors++;
-               if (tx_status & 0x0600)  dev->stats.tx_carrier_errors++;
-               if (tx_status & 0x0100)  dev->stats.tx_fifo_errors++;
-               if (!(tx_status & 0x0040))  dev->stats.tx_heartbeat_errors++;
-               if (tx_status & 0x0020)  dev->stats.tx_aborted_errors++;
-               dev->stats.collisions += tx_status & 0xf;
-         }
-         dev->stats.tx_packets++;
-         if (net_debug > 5)
-                 pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
-         lp->tx_reap += TX_BUF_SIZE;
-         if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
-               lp->tx_reap = TX_BUF_START;
-
-         lp->tx_pkts_in_ring--;
-         /* There is always more space in the Tx ring buffer now. */
-         netif_wake_queue(dev);
-
-         if (++boguscount > 10)
-               break;
-       }
-
-       if (status & 0x4000) { /* Packet received. */
-               if (net_debug > 5)
-                       pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
-               el16_rx(dev);
-       }
-
-       /* Acknowledge the interrupt sources. */
-       ack_cmd = status & 0xf000;
-
-       if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
-               if (net_debug)
-                       pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
-                                  dev->name, status);
-               /* If this ever occurs we should really re-write the idle loop, reset
-                  the Tx list, and do a complete restart of the command unit.
-                  For now we rely on the Tx timeout if the resume doesn't work. */
-               ack_cmd |= CUC_RESUME;
-       }
-
-       if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
-               /* The Rx unit is not ready, it must be hung.  Restart the receiver by
-                  initializing the rx buffers, and issuing an Rx start command. */
-               if (net_debug)
-                       pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
-                                  dev->name, status);
-               init_rx_bufs(dev);
-               writew(RX_BUF_START,shmem+iSCB_RFA);
-               ack_cmd |= RX_START;
-       }
-
-       writew(ack_cmd,shmem+iSCB_CMD);
-       outb(0, ioaddr + SIGNAL_CA);                    /* Issue channel-attn. */
-
-       /* Clear the latched interrupt. */
-       outb(0, ioaddr + RESET_IRQ);
-
-       /* Enable the 82586's interrupt input. */
-       outb(0x84, ioaddr + MISC_CTRL);
-       spin_unlock(&lp->lock);
-       return IRQ_HANDLED;
-}
-
-static int el16_close(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       void __iomem *shmem = lp->base;
-
-       netif_stop_queue(dev);
-
-       /* Flush the Tx and disable Rx. */
-       writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
-       outb(0, ioaddr + SIGNAL_CA);
-
-       /* Disable the 82586's input to the interrupt line. */
-       outb(0x80, ioaddr + MISC_CTRL);
-
-       /* We always physically use the IRQ line, so we don't do free_irq(). */
-
-       /* Update the statistics here. */
-
-       return 0;
-}
-
-/* Initialize the Rx-block list. */
-static void init_rx_bufs(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       void __iomem *write_ptr;
-       unsigned short SCB_base = SCB_BASE;
-
-       int cur_rxbuf = lp->rx_head = RX_BUF_START;
-
-       /* Initialize each Rx frame + data buffer. */
-       do {    /* While there is room for one more. */
-
-               write_ptr = lp->base + cur_rxbuf;
-
-               writew(0x0000,write_ptr);                       /* Status */
-               writew(0x0000,write_ptr+=2);                    /* Command */
-               writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2);   /* Link */
-               writew(cur_rxbuf + 22,write_ptr+=2);            /* Buffer offset */
-               writew(0x0000,write_ptr+=2);                    /* Pad for dest addr. */
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);                    /* Pad for source addr. */
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);
-               writew(0x0000,write_ptr+=2);                    /* Pad for protocol. */
-
-               writew(0x0000,write_ptr+=2);                    /* Buffer: Actual count */
-               writew(-1,write_ptr+=2);                        /* Buffer: Next (none). */
-               writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
-               writew(0x0000,write_ptr+=2);
-               /* Finally, the number of bytes in the buffer. */
-               writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
-
-               lp->rx_tail = cur_rxbuf;
-               cur_rxbuf += RX_BUF_SIZE;
-       } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
-
-       /* Terminate the list by setting the EOL bit, and wrap the pointer to make
-          the list a ring. */
-       write_ptr = lp->base + lp->rx_tail + 2;
-       writew(0xC000,write_ptr);                               /* Command, mark as last. */
-       writew(lp->rx_head,write_ptr+2);                        /* Link */
-}
-
-static void init_82586_mem(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       void __iomem *shmem = lp->base;
-
-       /* Enable loopback to protect the wire while starting up,
-          and hold the 586 in reset during the memory initialization. */
-       outb(0x20, ioaddr + MISC_CTRL);
-
-       /* Fix the ISCP address and base. */
-       init_words[3] = SCB_BASE;
-       init_words[7] = SCB_BASE;
-
-       /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
-       memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
-
-       /* Write the words at 0x0000. */
-       memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
-
-       /* Fill in the station address. */
-       memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
-
-       /* The Tx-block list is written as needed.  We just set up the values. */
-       lp->tx_cmd_link = IDLELOOP + 4;
-       lp->tx_head = lp->tx_reap = TX_BUF_START;
-
-       init_rx_bufs(dev);
-
-       /* Start the 586 by releasing the reset line, but leave loopback. */
-       outb(0xA0, ioaddr + MISC_CTRL);
-
-       /* This was time consuming to track down: you need to give two channel
-          attention signals to reliably start up the i82586. */
-       outb(0, ioaddr + SIGNAL_CA);
-
-       {
-               int boguscnt = 50;
-               while (readw(shmem+iSCB_STATUS) == 0)
-                       if (--boguscnt == 0) {
-                               pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
-                                       dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
-                               break;
-                       }
-               /* Issue channel-attn -- the 82586 won't start. */
-               outb(0, ioaddr + SIGNAL_CA);
-       }
-
-       /* Disable loopback and enable interrupts. */
-       outb(0x84, ioaddr + MISC_CTRL);
-       if (net_debug > 4)
-               pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
-                          readw(shmem+iSCB_STATUS));
-}
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
-{
-       struct net_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       ushort tx_block = lp->tx_head;
-       void __iomem *write_ptr = lp->base + tx_block;
-       static char padding[ETH_ZLEN];
-
-       /* Set the write pointer to the Tx block, and put out the header. */
-       writew(0x0000,write_ptr);                       /* Tx status */
-       writew(CMD_INTR|CmdTx,write_ptr+=2);            /* Tx command */
-       writew(tx_block+16,write_ptr+=2);               /* Next command is a NoOp. */
-       writew(tx_block+8,write_ptr+=2);                        /* Data Buffer offset. */
-
-       /* Output the data buffer descriptor. */
-       writew((pad + length) | 0x8000,write_ptr+=2);           /* Byte count parameter. */
-       writew(-1,write_ptr+=2);                        /* No next data buffer. */
-       writew(tx_block+22+SCB_BASE,write_ptr+=2);      /* Buffer follows the NoOp command. */
-       writew(0x0000,write_ptr+=2);                    /* Buffer address high bits (always zero). */
-
-       /* Output the Loop-back NoOp command. */
-       writew(0x0000,write_ptr+=2);                    /* Tx status */
-       writew(CmdNOp,write_ptr+=2);                    /* Tx command */
-       writew(tx_block+16,write_ptr+=2);               /* Next is myself. */
-
-       /* Output the packet at the write pointer. */
-       memcpy_toio(write_ptr+2, buf, length);
-       if (pad)
-               memcpy_toio(write_ptr+length+2, padding, pad);
-
-       /* Set the old command link pointing to this send packet. */
-       writew(tx_block,lp->base + lp->tx_cmd_link);
-       lp->tx_cmd_link = tx_block + 20;
-
-       /* Set the next free tx region. */
-       lp->tx_head = tx_block + TX_BUF_SIZE;
-       if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
-               lp->tx_head = TX_BUF_START;
-
-       if (net_debug > 4) {
-               pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
-                          dev->name, ioaddr, length, tx_block, lp->tx_head);
-       }
-
-       /* Grimly block further packets if there has been insufficient reaping. */
-       if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
-               netif_wake_queue(dev);
-}
-
-static void el16_rx(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       void __iomem *shmem = lp->base;
-       ushort rx_head = lp->rx_head;
-       ushort rx_tail = lp->rx_tail;
-       ushort boguscount = 10;
-       short frame_status;
-
-       while ((frame_status = readw(shmem+rx_head)) < 0) {   /* Command complete */
-               void __iomem *read_frame = lp->base + rx_head;
-               ushort rfd_cmd = readw(read_frame+2);
-               ushort next_rx_frame = readw(read_frame+4);
-               ushort data_buffer_addr = readw(read_frame+6);
-               void __iomem *data_frame = lp->base + data_buffer_addr;
-               ushort pkt_len = readw(data_frame);
-
-               if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
-                   (pkt_len & 0xC000) != 0xC000) {
-                       pr_err("%s: Rx frame at %#x corrupted, "
-                              "status %04x cmd %04x next %04x "
-                              "data-buf @%04x %04x.\n",
-                              dev->name, rx_head, frame_status, rfd_cmd,
-                              next_rx_frame, data_buffer_addr, pkt_len);
-               } else if ((frame_status & 0x2000) == 0) {
-                       /* Frame Rxed, but with error. */
-                       dev->stats.rx_errors++;
-                       if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
-                       if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
-                       if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
-                       if (frame_status & 0x0100) dev->stats.rx_over_errors++;
-                       if (frame_status & 0x0080) dev->stats.rx_length_errors++;
-               } else {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       pkt_len &= 0x3fff;
-                       skb = netdev_alloc_skb(dev, pkt_len + 2);
-                       if (skb == NULL) {
-                               pr_err("%s: Memory squeeze, dropping packet.\n",
-                                      dev->name);
-                               dev->stats.rx_dropped++;
-                               break;
-                       }
-
-                       skb_reserve(skb,2);
-
-                       /* 'skb->data' points to the start of sk_buff data area. */
-                       memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
-
-                       skb->protocol=eth_type_trans(skb,dev);
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-               }
-
-               /* Clear the status word and set End-of-List on the rx frame. */
-               writew(0,read_frame);
-               writew(0xC000,read_frame+2);
-               /* Clear the end-of-list on the prev. RFD. */
-               writew(0x0000,lp->base + rx_tail + 2);
-
-               rx_tail = rx_head;
-               rx_head = next_rx_frame;
-               if (--boguscount == 0)
-                       break;
-       }
-
-       lp->rx_head = rx_head;
-       lp->rx_tail = rx_tail;
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-       return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-       debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-       .get_msglevel           = netdev_get_msglevel,
-       .set_msglevel           = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-static struct net_device *dev_3c507;
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
-MODULE_PARM_DESC(irq, "(ignored)");
-
-int __init init_module(void)
-{
-       if (io == 0)
-               pr_notice("3c507: You should not use auto-probing with insmod!\n");
-       dev_3c507 = el16_probe(-1);
-       return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
-}
-
-void __exit
-cleanup_module(void)
-{
-       struct net_device *dev = dev_3c507;
-       unregister_netdev(dev);
-       free_irq(dev->irq, dev);
-       iounmap(((struct net_local *)netdev_priv(dev))->base);
-       release_region(dev->base_addr, EL16_IO_EXTENT);
-       free_netdev(dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
index 6aa927af382c7bff2a0b1b0d96bca0e2026f30ae..1c54e229e3cc94ed8ff0eb630bd9acc70cb20a8d 100644 (file)
@@ -95,9 +95,6 @@ static char version[] __initdata =
 #if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
 #define ENABLE_BVME6000_NET
 #endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_APRICOT_MODULE)
-#define ENABLE_APRICOT
-#endif
 
 #ifdef ENABLE_MVME16x_NET
 #include <asm/mvme16xhw.h>
@@ -120,8 +117,15 @@ static char version[] __initdata =
 #define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
 #define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
 #define ISCP_BUSY      0x00010000
-#define MACH_IS_APRICOT        0
 #else
+#error 82596.c: unknown architecture
+#endif
+
+/*
+ * These were the intel versions, left here for reference. There
+ * are currently no x86 users of this legacy i82596 chip.
+ */
+#if 0
 #define WSWAPrfd(x)     ((struct i596_rfd *)((long)x))
 #define WSWAPrbd(x)     ((struct i596_rbd *)((long)x))
 #define WSWAPiscp(x)    ((struct i596_iscp *)((long)x))
@@ -130,7 +134,6 @@ static char version[] __initdata =
 #define WSWAPtbd(x)     ((struct i596_tbd *)((long)x))
 #define WSWAPchar(x)    ((char *)((long)x))
 #define ISCP_BUSY      0x0001
-#define MACH_IS_APRICOT        1
 #endif
 
 /*
@@ -383,11 +386,6 @@ static inline void CA(struct net_device *dev)
                i = *(volatile u32 *) (dev->base_addr);
        }
 #endif
-#ifdef ENABLE_APRICOT
-       if (MACH_IS_APRICOT) {
-               outw(0, (short) (dev->base_addr) + 4);
-       }
-#endif
 }
 
 
@@ -617,9 +615,6 @@ static void rebuild_rx_bufs(struct net_device *dev)
 static int init_i596_mem(struct net_device *dev)
 {
        struct i596_private *lp = dev->ml_priv;
-#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
-       short ioaddr = dev->base_addr;
-#endif
        unsigned long flags;
 
        MPU_PORT(dev, PORT_RESET, NULL);
@@ -653,18 +648,6 @@ static int init_i596_mem(struct net_device *dev)
 
        MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
 
-#elif defined(ENABLE_APRICOT)
-
-       {
-               u32 scp = virt_to_bus(&lp->scp);
-
-               /* change the scp address */
-               outw(0, ioaddr);
-               outw(0, ioaddr);
-               outb(4, ioaddr + 0xf);
-               outw(scp | 2, ioaddr);
-               outw(scp >> 16, ioaddr);
-       }
 #endif
 
        lp->last_cmd = jiffies;
@@ -677,10 +660,6 @@ static int init_i596_mem(struct net_device *dev)
        if (MACH_IS_BVME6000)
                lp->scp.sysbus = 0x0000004c;
 #endif
-#ifdef ENABLE_APRICOT
-       if (MACH_IS_APRICOT)
-               lp->scp.sysbus = 0x00440000;
-#endif
 
        lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
        lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
@@ -698,10 +677,6 @@ static int init_i596_mem(struct net_device *dev)
 
        DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
 
-#if defined(ENABLE_APRICOT)
-       (void) inb(ioaddr + 0x10);
-       outb(4, ioaddr + 0xf);
-#endif
        CA(dev);
 
        if (wait_istat(dev,lp,1000,"initialization timed out"))
@@ -1202,43 +1177,6 @@ struct net_device * __init i82596_probe(int unit)
                dev->irq = (unsigned) BVME_IRQ_I596;
                goto found;
        }
-#endif
-#ifdef ENABLE_APRICOT
-       {
-               int checksum = 0;
-               int ioaddr = 0x300;
-
-               /* this is easy the ethernet interface can only be at 0x300 */
-               /* first check nothing is already registered here */
-
-               if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
-                       printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
-                       err = -EBUSY;
-                       goto out;
-               }
-
-               dev->base_addr = ioaddr;
-
-               for (i = 0; i < 8; i++) {
-                       eth_addr[i] = inb(ioaddr + 8 + i);
-                       checksum += eth_addr[i];
-               }
-
-               /* checksum is a multiple of 0x100, got this wrong first time
-                  some machines have 0x100, some 0x200. The DOS driver doesn't
-                  even bother with the checksum.
-                  Some other boards trip the checksum.. but then appear as
-                  ether address 0. Trap these - AC */
-
-               if ((checksum % 0x100) ||
-                   (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
-                       err = -ENODEV;
-                       goto out1;
-               }
-
-               dev->irq = 10;
-               goto found;
-       }
 #endif
        err = -ENODEV;
        goto out;
@@ -1296,9 +1234,6 @@ out2:
 #endif
        free_page ((u32)(dev->mem_start));
 out1:
-#ifdef ENABLE_APRICOT
-       release_region(dev->base_addr, I596_TOTAL_SIZE);
-#endif
 out:
        free_netdev(dev);
        return ERR_PTR(err);
@@ -1454,10 +1389,6 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
                *ethirq = 1;
                *ethirq = 3;
        }
-#endif
-#ifdef ENABLE_APRICOT
-       (void) inb(ioaddr + 0x10);
-       outb(4, ioaddr + 0xf);
 #endif
        CA(dev);
 
@@ -1589,11 +1520,6 @@ static void set_multicast_list(struct net_device *dev)
 #ifdef MODULE
 static struct net_device *dev_82596;
 
-#ifdef ENABLE_APRICOT
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq, "Apricot IRQ number");
-#endif
-
 static int debug = -1;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "i82596 debug mask");
@@ -1620,10 +1546,6 @@ void __exit cleanup_module(void)
                        IOMAP_FULL_CACHING);
 #endif
        free_page ((u32)(dev_82596->mem_start));
-#ifdef ENABLE_APRICOT
-       /* If we don't do this, we can't re-insmod it later. */
-       release_region(dev_82596->base_addr, I596_TOTAL_SIZE);
-#endif
        free_netdev(dev_82596);
 }
 
index 959faf7388e21ba77316d1817f66e337d6f89315..955d929cd00fc8cb757ee987a4c7fb53382339f7 100644 (file)
@@ -6,7 +6,7 @@ config NET_VENDOR_I825XX
        bool "Intel (82586/82593/82596) devices"
        default y
        depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \
-                  ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
+                  ARCH_ACORN || SNI_RM || SUN3 || \
                   GSC || BVME6000 || MVME16x || EXPERIMENTAL)
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
@@ -20,29 +20,6 @@ config NET_VENDOR_I825XX
 
 if NET_VENDOR_I825XX
 
-config ELPLUS
-       tristate "3c505 \"EtherLink Plus\" support"
-       depends on ISA && ISA_DMA_API
-       ---help---
-         Information about this network (Ethernet) card can be found in
-         <file:Documentation/networking/3c505.txt>.  If you have a card of
-         this type, say Y and read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c505.
-
-config EL16
-       tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
-       depends on ISA && EXPERIMENTAL
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called 3c507.
-
 config ARM_ETHER1
        tristate "Acorn Ether1 support"
        depends on ARM && ARCH_ACORN
@@ -50,17 +27,6 @@ config ARM_ETHER1
          If you have an Acorn system with one of these (AKA25) network cards,
          you should say Y to this option if you wish to use it with Linux.
 
-config APRICOT
-       tristate "Apricot Xen-II on board Ethernet"
-       depends on ISA
-       ---help---
-         If you have a network (Ethernet) controller of this type, say Y and
-         read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called apricot.
-
 config BVME6000_NET
        tristate "BVME6000 Ethernet support"
        depends on BVME6000
@@ -70,33 +36,6 @@ config BVME6000_NET
          in your kernel.
          To compile this driver as a module, choose M here.
 
-config EEXPRESS
-       tristate "EtherExpress 16 support"
-       depends on ISA
-       ---help---
-         If you have an EtherExpress16 network (Ethernet) card, say Y and
-         read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.  Note that the Intel
-         EtherExpress16 card used to be regarded as a very poor choice
-         because the driver was very unreliable. We now have a new driver
-         that should do better.
-
-         To compile this driver as a module, choose M here. The module
-         will be called eexpress.
-
-config EEXPRESS_PRO
-       tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
-       depends on ISA
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y. This
-         driver supports Intel i82595{FX,TX} based boards. Note however
-         that the EtherExpress PRO/100 Ethernet card has its own separate
-         driver.  Please read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called eepro.
-
 config LASI_82596
        tristate "Lasi ethernet"
        depends on GSC
@@ -104,14 +43,6 @@ config LASI_82596
          Say Y here to support the builtin Intel 82596 ethernet controller
          found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
 
-config LP486E
-       tristate "LP486E on board Ethernet"
-       depends on ISA
-       ---help---
-         Say Y here to support the 82596-based on-board Ethernet controller
-         for the Panther motherboard, which is one of the two shipped in the
-         Intel Professional Workstation.
-
 config MVME16x_NET
        tristate "MVME16x Ethernet support"
        depends on MVME16x
@@ -121,17 +52,6 @@ config MVME16x_NET
          driver for this chip in your kernel.
          To compile this driver as a module, choose M here.
 
-config NI52
-       tristate "NI5210 support"
-       depends on ISA
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called ni52.
-
 config SNI_82596
        tristate "SNI RM ethernet"
        depends on SNI_RM
@@ -148,14 +68,4 @@ config SUN3_82586
          that this driver does not support 82586-based adapters on additional
          VME boards.
 
-config ZNET
-       tristate "Zenith Z-Note support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && ISA_DMA_API && X86
-       ---help---
-         The Zenith Z-Note notebook computer has a built-in network
-         (Ethernet) card, and this is the Linux driver for it. Note that the
-         IBM Thinkpad 300 is compatible with the Z-Note and is also supported
-         by this driver. Read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
 endif # NET_VENDOR_I825XX
index 6adff85e8ecc3bcefe25c3f408e1e3d39c9f8b08..8c8dcd29c40d45e86f6f2a73bebf2c417aadceb2 100644 (file)
@@ -3,15 +3,7 @@
 #
 
 obj-$(CONFIG_ARM_ETHER1) += ether1.o
-obj-$(CONFIG_EEXPRESS) += eexpress.o
-obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_ELPLUS) += 3c505.o
-obj-$(CONFIG_EL16) += 3c507.o
-obj-$(CONFIG_LP486E) += lp486e.o
-obj-$(CONFIG_NI52) += ni52.o
 obj-$(CONFIG_SUN3_82586) += sun3_82586.o
-obj-$(CONFIG_ZNET) += znet.o
-obj-$(CONFIG_APRICOT) += 82596.o
 obj-$(CONFIG_LASI_82596) += lasi_82596.o
 obj-$(CONFIG_SNI_82596) += sni_82596.o
 obj-$(CONFIG_MVME16x_NET) += 82596.o
diff --git a/drivers/net/ethernet/i825xx/eepro.c b/drivers/net/ethernet/i825xx/eepro.c
deleted file mode 100644 (file)
index 7f49fd5..0000000
+++ /dev/null
@@ -1,1822 +0,0 @@
-/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
-/*
-       Written 1994, 1995,1996 by Bao C. Ha.
-
-       Copyright (C) 1994, 1995,1996 by Bao C. Ha.
-
-       This software may be used and distributed
-       according to the terms of the GNU General Public License,
-       incorporated herein by reference.
-
-       The author may be reached at bao.ha@srs.gov
-       or 418 Hastings Place, Martinez, GA 30907.
-
-       Things remaining to do:
-       Better record keeping of errors.
-       Eliminate transmit interrupt to reduce overhead.
-       Implement "concurrent processing". I won't be doing it!
-
-       Bugs:
-
-       If you have a problem of not detecting the 82595 during a
-       reboot (warm reset), disable the FLASH memory should fix it.
-       This is a compatibility hardware problem.
-
-       Versions:
-       0.13b   basic ethtool support (aris, 09/13/2004)
-       0.13a   in memory shortage, drop packets also in board
-               (Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
-       0.13    irq sharing, rewrote probe function, fixed a nasty bug in
-               hardware_send_packet and a major cleanup (aris, 11/08/2001)
-       0.12d   fixing a problem with single card detected as eight eth devices
-               fixing a problem with sudden drop in card performance
-               (chris (asdn@go2.pl), 10/29/2001)
-       0.12c   fixing some problems with old cards (aris, 01/08/2001)
-       0.12b   misc fixes (aris, 06/26/2000)
-       0.12a   port of version 0.12a of 2.2.x kernels to 2.3.x
-               (aris (aris@conectiva.com.br), 05/19/2000)
-       0.11e   some tweaks about multiple cards support (PdP, jul/aug 1999)
-       0.11d   added __initdata, __init stuff; call spin_lock_init
-               in eepro_probe1. Replaced "eepro" by dev->name. Augmented
-               the code protected by spin_lock in interrupt routine
-               (PdP, 12/12/1998)
-       0.11c   minor cleanup (PdP, RMC, 09/12/1998)
-       0.11b   Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module
-               under 2.1.xx. Debug messages are flagged as KERN_DEBUG to
-               avoid console flooding. Added locking at critical parts. Now
-               the dawn thing is SMP safe.
-       0.11a   Attempt to get 2.1.xx support up (RMC)
-       0.11    Brian Candler added support for multiple cards. Tested as
-               a module, no idea if it works when compiled into kernel.
-
-       0.10e   Rick Bressler notified me that ifconfig up;ifconfig down fails
-               because the irq is lost somewhere. Fixed that by moving
-               request_irq and free_irq to eepro_open and eepro_close respectively.
-       0.10d   Ugh! Now Wakeup works. Was seriously broken in my first attempt.
-               I'll need to find a way to specify an ioport other than
-               the default one in the PnP case. PnP definitively sucks.
-               And, yes, this is not the only reason.
-       0.10c   PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
-               to use.
-       0.10b   Should work now with (some) Pro/10+. At least for
-               me (and my two cards) it does. _No_ guarantee for
-               function with non-Pro/10+ cards! (don't have any)
-               (RMC, 9/11/96)
-
-       0.10    Added support for the Etherexpress Pro/10+.  The
-               IRQ map was changed significantly from the old
-               pro/10.  The new interrupt map was provided by
-               Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
-               (BCH, 9/3/96)
-
-       0.09    Fixed a race condition in the transmit algorithm,
-               which causes crashes under heavy load with fast
-               pentium computers.  The performance should also
-               improve a bit.  The size of RX buffer, and hence
-               TX buffer, can also be changed via lilo or insmod.
-               (BCH, 7/31/96)
-
-       0.08    Implement 32-bit I/O for the 82595TX and 82595FX
-               based lan cards.  Disable full-duplex mode if TPE
-               is not used.  (BCH, 4/8/96)
-
-       0.07a   Fix a stat report which counts every packet as a
-               heart-beat failure. (BCH, 6/3/95)
-
-       0.07    Modified to support all other 82595-based lan cards.
-               The IRQ vector of the EtherExpress Pro will be set
-               according to the value saved in the EEPROM.  For other
-               cards, I will do autoirq_request() to grab the next
-               available interrupt vector. (BCH, 3/17/95)
-
-       0.06a,b Interim released.  Minor changes in the comments and
-               print out format. (BCH, 3/9/95 and 3/14/95)
-
-       0.06    First stable release that I am comfortable with. (BCH,
-               3/2/95)
-
-       0.05    Complete testing of multicast. (BCH, 2/23/95)
-
-       0.04    Adding multicast support. (BCH, 2/14/95)
-
-       0.03    First widely alpha release for public testing.
-               (BCH, 2/14/95)
-
-*/
-
-static const char version[] =
-       "eepro.c: v0.13b 09/13/2004 aris@cathedrallabs.org\n";
-
-#include <linux/module.h>
-
-/*
-  Sources:
-
-       This driver wouldn't have been written without the availability
-       of the Crynwr's Lan595 driver source code.  It helps me to
-       familiarize with the 82595 chipset while waiting for the Intel
-       documentation.  I also learned how to detect the 82595 using
-       the packet driver's technique.
-
-       This driver is written by cutting and pasting the skeleton.c driver
-       provided by Donald Becker.  I also borrowed the EEPROM routine from
-       Donald Becker's 82586 driver.
-
-       Datasheet for the Intel 82595 (including the TX and FX version). It
-       provides just enough info that the casual reader might think that it
-       documents the i82595.
-
-       The User Manual for the 82595.  It provides a lot of the missing
-       information.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/ethtool.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "eepro"
-#define DRV_VERSION "0.13c"
-
-#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
-/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
-#define SLOW_DOWN inb(0x80)
-/* udelay(2) */
-#define compat_init_data     __initdata
-enum iftype { AUI=0, BNC=1, TPE=2 };
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int eepro_portlist[] compat_init_data =
-   { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
-/* note: 0x300 is default, the 595FX supports ALL IO Ports
-  from 0x000 to 0x3F0, some of which are reserved in PCs */
-
-/* To try the (not-really PnP Wakeup: */
-/*
-#define PnPWakeup
-*/
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define EEPRO_IO_EXTENT        16
-
-/* Different 82595 chips */
-#define        LAN595          0
-#define        LAN595TX        1
-#define        LAN595FX        2
-#define        LAN595FX_10ISA  3
-
-/* Information that need to be kept for each board. */
-struct eepro_local {
-       unsigned rx_start;
-       unsigned tx_start; /* start of the transmit chain */
-       int tx_last;  /* pointer to last packet in the transmit chain */
-       unsigned tx_end;   /* end of the transmit chain (plus 1) */
-       int eepro;      /* 1 for the EtherExpress Pro/10,
-                          2 for the EtherExpress Pro/10+,
-                          3 for the EtherExpress 10 (blue cards),
-                          0 for other 82595-based lan cards. */
-       int version;    /* a flag to indicate if this is a TX or FX
-                                  version of the 82595 chip. */
-       int stepping;
-
-       spinlock_t lock; /* Serializing lock  */
-
-       unsigned rcv_ram;       /* pre-calculated space for rx */
-       unsigned xmt_ram;       /* pre-calculated space for tx */
-       unsigned char xmt_bar;
-       unsigned char xmt_lower_limit_reg;
-       unsigned char xmt_upper_limit_reg;
-       short xmt_lower_limit;
-       short xmt_upper_limit;
-       short rcv_lower_limit;
-       short rcv_upper_limit;
-       unsigned char eeprom_reg;
-       unsigned short word[8];
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00  /* Etherexpress Pro/10 */
-#define SA_ADDR1 0xaa
-#define SA_ADDR2 0x00
-
-#define GetBit(x,y) ((x & (1<<y))>>y)
-
-/* EEPROM Word 0: */
-#define ee_PnP       0  /* Plug 'n Play enable bit */
-#define ee_Word1     1  /* Word 1? */
-#define ee_BusWidth  2  /* 8/16 bit */
-#define ee_FlashAddr 3  /* Flash Address */
-#define ee_FlashMask 0x7   /* Mask */
-#define ee_AutoIO    6  /* */
-#define ee_reserved0 7  /* =0! */
-#define ee_Flash     8  /* Flash there? */
-#define ee_AutoNeg   9  /* Auto Negotiation enabled? */
-#define ee_IO0       10 /* IO Address LSB */
-#define ee_IO0Mask   0x /*...*/
-#define ee_IO1       15 /* IO MSB */
-
-/* EEPROM Word 1: */
-#define ee_IntSel    0   /* Interrupt */
-#define ee_IntMask   0x7
-#define ee_LI        3   /* Link Integrity 0= enabled */
-#define ee_PC        4   /* Polarity Correction 0= enabled */
-#define ee_TPE_AUI   5   /* PortSelection 1=TPE */
-#define ee_Jabber    6   /* Jabber prevention 0= enabled */
-#define ee_AutoPort  7   /* Auto Port Selection 1= Disabled */
-#define ee_SMOUT     8   /* SMout Pin Control 0= Input */
-#define ee_PROM      9   /* Flash EPROM / PROM 0=Flash */
-#define ee_reserved1 10  /* .. 12 =0! */
-#define ee_AltReady  13  /* Alternate Ready, 0=normal */
-#define ee_reserved2 14  /* =0! */
-#define ee_Duplex    15
-
-/* Word2,3,4: */
-#define ee_IA5       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA4       8 /*bit start for individual Addr Byte 5 */
-#define ee_IA3       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA2       8 /*bit start for individual Addr Byte 5 */
-#define ee_IA1       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA0       8 /*bit start for individual Addr Byte 5 */
-
-/* Word 5: */
-#define ee_BNC_TPE   0 /* 0=TPE */
-#define ee_BootType  1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
-#define ee_BootTypeMask 0x3
-#define ee_NumConn   3  /* Number of Connections 0= One or Two */
-#define ee_FlashSock 4  /* Presence of Flash Socket 0= Present */
-#define ee_PortTPE   5
-#define ee_PortBNC   6
-#define ee_PortAUI   7
-#define ee_PowerMgt  10 /* 0= disabled */
-#define ee_CP        13 /* Concurrent Processing */
-#define ee_CPMask    0x7
-
-/* Word 6: */
-#define ee_Stepping  0 /* Stepping info */
-#define ee_StepMask  0x0F
-#define ee_BoardID   4 /* Manucaturer Board ID, reserved */
-#define ee_BoardMask 0x0FFF
-
-/* Word 7: */
-#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping  = 0x1EB8 for Pro/10+ */
-#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
-
-/*..*/
-#define ee_SIZE 0x40 /* total EEprom Size */
-#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
-
-
-/* Card identification via EEprom:   */
-#define ee_addr_vendor 0x10  /* Word offset for EISA Vendor ID */
-#define ee_addr_id 0x11      /* Word offset for Card ID */
-#define ee_addr_SN 0x12      /* Serial Number */
-#define ee_addr_CRC_8 0x14   /* CRC over last thee Bytes */
-
-
-#define ee_vendor_intel0 0x25  /* Vendor ID Intel */
-#define ee_vendor_intel1 0xD4
-#define ee_id_eepro10p0 0x10   /* ID for eepro/10+ */
-#define ee_id_eepro10p1 0x31
-
-#define TX_TIMEOUT ((4*HZ)/10)
-
-/* Index to functions, as function prototypes. */
-
-static int     eepro_probe1(struct net_device *dev, int autoprobe);
-static int     eepro_open(struct net_device *dev);
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
-                                    struct net_device *dev);
-static irqreturn_t eepro_interrupt(int irq, void *dev_id);
-static void    eepro_rx(struct net_device *dev);
-static void    eepro_transmit_interrupt(struct net_device *dev);
-static int     eepro_close(struct net_device *dev);
-static void     set_multicast_list(struct net_device *dev);
-static void     eepro_tx_timeout (struct net_device *dev);
-
-static int read_eeprom(int ioaddr, int location, struct net_device *dev);
-static int     hardware_send_packet(struct net_device *dev, void *buf, short length);
-static int     eepro_grab_irq(struct net_device *dev);
-
-/*
-                       Details of the i82595.
-
-You will need either the datasheet or the user manual to understand what
-is going on here.  The 82595 is very different from the 82586, 82593.
-
-The receive algorithm in eepro_rx() is just an implementation of the
-RCV ring structure that the Intel 82595 imposes at the hardware level.
-The receive buffer is set at 24K, and the transmit buffer is 8K.  I
-am assuming that the total buffer memory is 32K, which is true for the
-Intel EtherExpress Pro/10.  If it is less than that on a generic card,
-the driver will be broken.
-
-The transmit algorithm in the hardware_send_packet() is similar to the
-one in the eepro_rx().  The transmit buffer is a ring linked list.
-I just queue the next available packet to the end of the list.  In my
-system, the 82595 is so fast that the list seems to always contain a
-single packet.  In other systems with faster computers and more congested
-network traffics, the ring linked list should improve performance by
-allowing up to 8K worth of packets to be queued.
-
-The sizes of the receive and transmit buffers can now be changed via lilo
-or insmod.  Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
-where rx-buffer is in KB unit.  Modules uses the parameter mem which is
-also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
-The receive buffer has to be more than 3K or less than 29K.  Otherwise,
-it is reset to the default of 24K, and, hence, 8K for the trasnmit
-buffer (transmit-buffer = 32K - receive-buffer).
-
-*/
-#define RAM_SIZE        0x8000
-
-#define RCV_HEADER      8
-#define RCV_DEFAULT_RAM 0x6000
-
-#define XMT_HEADER      8
-#define XMT_DEFAULT_RAM        (RAM_SIZE - RCV_DEFAULT_RAM)
-
-#define XMT_START_PRO  RCV_DEFAULT_RAM
-#define XMT_START_10   0x0000
-#define RCV_START_PRO  0x0000
-#define RCV_START_10   XMT_DEFAULT_RAM
-
-#define        RCV_DONE        0x0008
-#define        RX_OK           0x2000
-#define        RX_ERROR        0x0d81
-
-#define        TX_DONE_BIT     0x0080
-#define        TX_OK           0x2000
-#define        CHAIN_BIT       0x8000
-#define        XMT_STATUS      0x02
-#define        XMT_CHAIN       0x04
-#define        XMT_COUNT       0x06
-
-#define        BANK0_SELECT    0x00
-#define        BANK1_SELECT    0x40
-#define        BANK2_SELECT    0x80
-
-/* Bank 0 registers */
-#define        COMMAND_REG     0x00    /* Register 0 */
-#define        MC_SETUP        0x03
-#define        XMT_CMD         0x04
-#define        DIAGNOSE_CMD    0x07
-#define        RCV_ENABLE_CMD  0x08
-#define        RCV_DISABLE_CMD 0x0a
-#define        STOP_RCV_CMD    0x0b
-#define        RESET_CMD       0x0e
-#define        POWER_DOWN_CMD  0x18
-#define        RESUME_XMT_CMD  0x1c
-#define        SEL_RESET_CMD   0x1e
-#define        STATUS_REG      0x01    /* Register 1 */
-#define        RX_INT          0x02
-#define        TX_INT          0x04
-#define        EXEC_STATUS     0x30
-#define        ID_REG          0x02    /* Register 2   */
-#define        R_ROBIN_BITS    0xc0    /* round robin counter */
-#define        ID_REG_MASK     0x2c
-#define        ID_REG_SIG      0x24
-#define        AUTO_ENABLE     0x10
-#define        INT_MASK_REG    0x03    /* Register 3   */
-#define        RX_STOP_MASK    0x01
-#define        RX_MASK         0x02
-#define        TX_MASK         0x04
-#define        EXEC_MASK       0x08
-#define        ALL_MASK        0x0f
-#define        IO_32_BIT       0x10
-#define        RCV_BAR         0x04    /* The following are word (16-bit) registers */
-#define        RCV_STOP        0x06
-
-#define        XMT_BAR_PRO     0x0a
-#define        XMT_BAR_10      0x0b
-
-#define        HOST_ADDRESS_REG        0x0c
-#define        IO_PORT         0x0e
-#define        IO_PORT_32_BIT  0x0c
-
-/* Bank 1 registers */
-#define        REG1    0x01
-#define        WORD_WIDTH      0x02
-#define        INT_ENABLE      0x80
-#define INT_NO_REG     0x02
-#define        RCV_LOWER_LIMIT_REG     0x08
-#define        RCV_UPPER_LIMIT_REG     0x09
-
-#define        XMT_LOWER_LIMIT_REG_PRO 0x0a
-#define        XMT_UPPER_LIMIT_REG_PRO 0x0b
-#define        XMT_LOWER_LIMIT_REG_10  0x0b
-#define        XMT_UPPER_LIMIT_REG_10  0x0a
-
-/* Bank 2 registers */
-#define        XMT_Chain_Int   0x20    /* Interrupt at the end of the transmit chain */
-#define        XMT_Chain_ErrStop       0x40 /* Interrupt at the end of the chain even if there are errors */
-#define        RCV_Discard_BadFrame    0x80 /* Throw bad frames away, and continue to receive others */
-#define        REG2            0x02
-#define        PRMSC_Mode      0x01
-#define        Multi_IA        0x20
-#define        REG3            0x03
-#define        TPE_BIT         0x04
-#define        BNC_BIT         0x20
-#define        REG13           0x0d
-#define        FDX             0x00
-#define        A_N_ENABLE      0x02
-
-#define        I_ADD_REG0      0x04
-#define        I_ADD_REG1      0x05
-#define        I_ADD_REG2      0x06
-#define        I_ADD_REG3      0x07
-#define        I_ADD_REG4      0x08
-#define        I_ADD_REG5      0x09
-
-#define        EEPROM_REG_PRO 0x0a
-#define        EEPROM_REG_10  0x0b
-
-#define EESK 0x01
-#define EECS 0x02
-#define EEDI 0x04
-#define EEDO 0x08
-
-/* do a full reset */
-#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
-
-/* do a nice reset */
-#define eepro_sel_reset(ioaddr)        { \
-                                       outb(SEL_RESET_CMD, ioaddr); \
-                                       SLOW_DOWN; \
-                                       SLOW_DOWN; \
-                                       }
-
-/* disable all interrupts */
-#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
-
-/* clear all interrupts */
-#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
-
-/* enable tx/rx */
-#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
-                                                       ioaddr + INT_MASK_REG)
-
-/* enable exec event interrupt */
-#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
-
-/* enable rx */
-#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
-
-/* disable rx */
-#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
-
-/* switch bank */
-#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
-#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
-#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
-
-/* enable interrupt line */
-#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
-                               ioaddr + REG1)
-
-/* disable interrupt line */
-#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
-                               ioaddr + REG1);
-
-/* set diagnose flag */
-#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
-
-/* ack for rx int */
-#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
-
-/* ack for tx int */
-#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
-
-/* a complete sel reset */
-#define eepro_complete_selreset(ioaddr) { \
-                                               dev->stats.tx_errors++;\
-                                               eepro_sel_reset(ioaddr);\
-                                               lp->tx_end = \
-                                                       lp->xmt_lower_limit;\
-                                               lp->tx_start = lp->tx_end;\
-                                               lp->tx_last = 0;\
-                                               dev->trans_start = jiffies;\
-                                               netif_wake_queue(dev);\
-                                               eepro_en_rx(ioaddr);\
-                                       }
-
-/* Check for a network adaptor of this type, and return '0' if one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, allocate space for the device and return success
-   (detachable devices only).
-   */
-static int __init do_eepro_probe(struct net_device *dev)
-{
-       int i;
-       int base_addr = dev->base_addr;
-       int irq = dev->irq;
-
-#ifdef PnPWakeup
-       /* XXXX for multiple cards should this only be run once? */
-
-       /* Wakeup: */
-       #define WakeupPort 0x279
-       #define WakeupSeq    {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
-                             0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
-                             0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
-                             0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
-
-       {
-               unsigned short int WS[32]=WakeupSeq;
-
-               if (request_region(WakeupPort, 2, "eepro wakeup")) {
-                       if (net_debug>5)
-                               printk(KERN_DEBUG "Waking UP\n");
-
-                       outb_p(0,WakeupPort);
-                       outb_p(0,WakeupPort);
-                       for (i=0; i<32; i++) {
-                               outb_p(WS[i],WakeupPort);
-                               if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
-                       }
-
-                       release_region(WakeupPort, 2);
-               } else
-                       printk(KERN_WARNING "PnP wakeup region busy!\n");
-       }
-#endif
-
-       if (base_addr > 0x1ff)          /* Check a single specified location. */
-               return eepro_probe1(dev, 0);
-
-       else if (base_addr != 0)        /* Don't probe at all. */
-               return -ENXIO;
-
-       for (i = 0; eepro_portlist[i]; i++) {
-               dev->base_addr = eepro_portlist[i];
-               dev->irq = irq;
-               if (eepro_probe1(dev, 1) == 0)
-                       return 0;
-       }
-
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eepro_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_eepro_probe(dev);
-       if (err)
-               goto out;
-       return dev;
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-static void __init printEEPROMInfo(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned short Word;
-       int i,j;
-
-       j = ee_Checksum;
-       for (i = 0; i < 8; i++)
-               j += lp->word[i];
-       for ( ; i < ee_SIZE; i++)
-               j += read_eeprom(ioaddr, i, dev);
-
-       printk(KERN_DEBUG "Checksum: %#x\n",j&0xffff);
-
-       Word = lp->word[0];
-       printk(KERN_DEBUG "Word0:\n");
-       printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
-       printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
-       printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg));
-       printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
-
-       if (net_debug>4)  {
-               Word = lp->word[1];
-               printk(KERN_DEBUG "Word1:\n");
-               printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
-               printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
-               printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
-               printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
-               printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
-               printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
-               printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
-       }
-
-       Word = lp->word[5];
-       printk(KERN_DEBUG "Word5:\n");
-       printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
-       printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
-       printk(KERN_DEBUG " Has ");
-       if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
-       if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
-       if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
-       printk(KERN_DEBUG "port(s)\n");
-
-       Word = lp->word[6];
-       printk(KERN_DEBUG "Word6:\n");
-       printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
-       printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
-
-       Word = lp->word[7];
-       printk(KERN_DEBUG "Word7:\n");
-       printk(KERN_DEBUG " INT to IRQ:\n");
-
-       for (i=0, j=0; i<15; i++)
-               if (GetBit(Word,i)) printk(KERN_DEBUG " INT%d -> IRQ %d;",j++,i);
-
-       printk(KERN_DEBUG "\n");
-}
-
-/* function to recalculate the limits of buffer based on rcv_ram */
-static void eepro_recalc (struct net_device *dev)
-{
-       struct eepro_local *    lp;
-
-       lp = netdev_priv(dev);
-       lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
-
-       if (lp->eepro == LAN595FX_10ISA) {
-               lp->xmt_lower_limit = XMT_START_10;
-               lp->xmt_upper_limit = (lp->xmt_ram - 2);
-               lp->rcv_lower_limit = lp->xmt_ram;
-               lp->rcv_upper_limit = (RAM_SIZE - 2);
-       }
-       else {
-               lp->rcv_lower_limit = RCV_START_PRO;
-               lp->rcv_upper_limit = (lp->rcv_ram - 2);
-               lp->xmt_lower_limit = lp->rcv_ram;
-               lp->xmt_upper_limit = (RAM_SIZE - 2);
-       }
-}
-
-/* prints boot-time info */
-static void __init eepro_print_info (struct net_device *dev)
-{
-       struct eepro_local *    lp = netdev_priv(dev);
-       int                     i;
-       const char *            ifmap[] = {"AUI", "10Base2", "10BaseT"};
-
-       i = inb(dev->base_addr + ID_REG);
-       printk(KERN_DEBUG " id: %#x ",i);
-       printk(" io: %#x ", (unsigned)dev->base_addr);
-
-       switch (lp->eepro) {
-               case LAN595FX_10ISA:
-                       printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-               case LAN595FX:
-                       printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-               case LAN595TX:
-                       printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-               case LAN595:
-                       printk("%s: Intel 82595-based lan card at %#x,",
-                                       dev->name, (unsigned)dev->base_addr);
-                       break;
-       }
-
-       printk(" %pM", dev->dev_addr);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG ", %dK RCV buffer",
-                               (int)(lp->rcv_ram)/1024);
-
-       if (dev->irq > 2)
-               printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
-       else
-               printk(", %s.\n", ifmap[dev->if_port]);
-
-       if (net_debug > 3) {
-               i = lp->word[5];
-               if (i & 0x2000) /* bit 13 of EEPROM word 5 */
-                       printk(KERN_DEBUG "%s: Concurrent Processing is "
-                               "enabled but not used!\n", dev->name);
-       }
-
-       /* Check the station address for the manufacturer's code */
-       if (net_debug>3)
-               printEEPROMInfo(dev);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops;
-
-static const struct net_device_ops eepro_netdev_ops = {
-       .ndo_open               = eepro_open,
-       .ndo_stop               = eepro_close,
-       .ndo_start_xmit         = eepro_send_packet,
-       .ndo_set_rx_mode        = set_multicast_list,
-       .ndo_tx_timeout         = eepro_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/* This is the real probe routine.  Linux has a history of friendly device
-   probes on the ISA bus.  A good device probe avoids doing writes, and
-   verifies that the correct device exists and functions.  */
-
-static int __init eepro_probe1(struct net_device *dev, int autoprobe)
-{
-       unsigned short station_addr[3], id, counter;
-       int i;
-       struct eepro_local *lp;
-       int ioaddr = dev->base_addr;
-       int err;
-
-       /* Grab the region so we can find another board if autoIRQ fails. */
-       if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
-               if (!autoprobe)
-                       printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
-                               ioaddr);
-               return -EBUSY;
-       }
-
-       /* Now, we are going to check for the signature of the
-          ID_REG (register 2 of bank 0) */
-
-       id = inb(ioaddr + ID_REG);
-
-       if ((id & ID_REG_MASK) != ID_REG_SIG)
-               goto exit;
-
-       /* We seem to have the 82595 signature, let's
-          play with its counter (last 2 bits of
-          register 2 of bank 0) to be sure. */
-
-       counter = id & R_ROBIN_BITS;
-
-       if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
-               goto exit;
-
-       lp = netdev_priv(dev);
-       memset(lp, 0, sizeof(struct eepro_local));
-       lp->xmt_bar = XMT_BAR_PRO;
-       lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
-       lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
-       lp->eeprom_reg = EEPROM_REG_PRO;
-       spin_lock_init(&lp->lock);
-
-       /* Now, get the ethernet hardware address from
-          the EEPROM */
-       station_addr[0] = read_eeprom(ioaddr, 2, dev);
-
-       /* FIXME - find another way to know that we've found
-        * an Etherexpress 10
-        */
-       if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) {
-               lp->eepro = LAN595FX_10ISA;
-               lp->eeprom_reg = EEPROM_REG_10;
-               lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
-               lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
-               lp->xmt_bar = XMT_BAR_10;
-               station_addr[0] = read_eeprom(ioaddr, 2, dev);
-       }
-
-       /* get all words at once. will be used here and for ethtool */
-       for (i = 0; i < 8; i++) {
-               lp->word[i] = read_eeprom(ioaddr, i, dev);
-       }
-       station_addr[1] = lp->word[3];
-       station_addr[2] = lp->word[4];
-
-       if (!lp->eepro) {
-               if (lp->word[7] == ee_FX_INT2IRQ)
-                       lp->eepro = 2;
-               else if (station_addr[2] == SA_ADDR1)
-                       lp->eepro = 1;
-       }
-
-       /* Fill in the 'dev' fields. */
-       for (i=0; i < 6; i++)
-               dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
-
-       /* RX buffer must be more than 3K and less than 29K */
-       if (dev->mem_end < 3072 || dev->mem_end > 29696)
-               lp->rcv_ram = RCV_DEFAULT_RAM;
-
-       /* calculate {xmt,rcv}_{lower,upper}_limit */
-       eepro_recalc(dev);
-
-       if (GetBit(lp->word[5], ee_BNC_TPE))
-               dev->if_port = BNC;
-       else
-               dev->if_port = TPE;
-
-       if (dev->irq < 2 && lp->eepro != 0) {
-               /* Mask off INT number */
-               int count = lp->word[1] & 7;
-               unsigned irqMask = lp->word[7];
-
-               while (count--)
-                       irqMask &= irqMask - 1;
-
-               count = ffs(irqMask);
-
-               if (count)
-                       dev->irq = count - 1;
-
-               if (dev->irq < 2) {
-                       printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
-                       goto exit;
-               } else if (dev->irq == 2) {
-                       dev->irq = 9;
-               }
-       }
-
-       dev->netdev_ops         = &eepro_netdev_ops;
-       dev->watchdog_timeo     = TX_TIMEOUT;
-       dev->ethtool_ops        = &eepro_ethtool_ops;
-
-       /* print boot time info */
-       eepro_print_info(dev);
-
-       /* reset 82595 */
-       eepro_reset(ioaddr);
-
-       err = register_netdev(dev);
-       if (err)
-               goto err;
-       return 0;
-exit:
-       err = -ENODEV;
-err:
-       release_region(dev->base_addr, EEPRO_IO_EXTENT);
-       return err;
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-   */
-
-static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
-static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
-static int     eepro_grab_irq(struct net_device *dev)
-{
-       static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
-       const int *irqp = irqlist;
-       int temp_reg, ioaddr = dev->base_addr;
-
-       eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-       /* Enable the interrupt line. */
-       eepro_en_intline(ioaddr);
-
-       /* be CAREFUL, BANK 0 now */
-       eepro_sw2bank0(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       /* Let EXEC event to interrupt */
-       eepro_en_intexec(ioaddr);
-
-       do {
-               eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-               temp_reg = inb(ioaddr + INT_NO_REG);
-               outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
-
-               eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-               if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
-                       unsigned long irq_mask;
-                       /* Twinkle the interrupt, and check if it's seen */
-                       irq_mask = probe_irq_on();
-
-                       eepro_diag(ioaddr); /* RESET the 82595 */
-                       mdelay(20);
-
-                       if (*irqp == probe_irq_off(irq_mask))  /* It's a good IRQ line */
-                               break;
-
-                       /* clear all interrupts */
-                       eepro_clear_int(ioaddr);
-               }
-       } while (*++irqp);
-
-       eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
-       /* Disable the physical interrupt line. */
-       eepro_dis_intline(ioaddr);
-
-       eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-       /* Mask all the interrupts. */
-       eepro_dis_int(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       return dev->irq;
-}
-
-static int eepro_open(struct net_device *dev)
-{
-       unsigned short temp_reg, old8, old9;
-       int irqMask;
-       int i, ioaddr = dev->base_addr;
-       struct eepro_local *lp = netdev_priv(dev);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
-
-       irqMask = lp->word[7];
-
-       if (lp->eepro == LAN595FX_10ISA) {
-               if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
-       }
-       else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
-               {
-                       lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
-                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
-               }
-
-       else if ((dev->dev_addr[0] == SA_ADDR0 &&
-                       dev->dev_addr[1] == SA_ADDR1 &&
-                       dev->dev_addr[2] == SA_ADDR2))
-               {
-                       lp->eepro = 1;
-                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n");
-               }  /* Yes, an Intel EtherExpress Pro/10 */
-
-       else lp->eepro = 0; /* No, it is a generic 82585 lan card */
-
-       /* Get the interrupt vector for the 82595 */
-       if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
-               printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-
-       if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) {
-               printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-
-       /* Initialize the 82595. */
-
-       eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-       temp_reg = inb(ioaddr + lp->eeprom_reg);
-
-       lp->stepping = temp_reg >> 5;   /* Get the stepping number of the 595 */
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
-
-       if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
-               outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg);
-       for (i=0; i < 6; i++)
-               outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
-
-       temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
-       outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
-               | RCV_Discard_BadFrame, ioaddr + REG1);
-
-       temp_reg = inb(ioaddr + REG2); /* Match broadcast */
-       outb(temp_reg | 0x14, ioaddr + REG2);
-
-       temp_reg = inb(ioaddr + REG3);
-       outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
-
-       /* Set the receiving mode */
-       eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-       /* Set the interrupt vector */
-       temp_reg = inb(ioaddr + INT_NO_REG);
-       if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
-               outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
-       else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-
-       temp_reg = inb(ioaddr + INT_NO_REG);
-       if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
-               outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
-       else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
-
-
-       /* Initialize the RCV and XMT upper and lower limits */
-       outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG);
-       outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG);
-       outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg);
-       outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg);
-
-       /* Enable the interrupt line. */
-       eepro_en_intline(ioaddr);
-
-       /* Switch back to Bank 0 */
-       eepro_sw2bank0(ioaddr);
-
-       /* Let RX and TX events to interrupt */
-       eepro_en_int(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       /* Initialize RCV */
-       outw(lp->rcv_lower_limit, ioaddr + RCV_BAR);
-       lp->rx_start = lp->rcv_lower_limit;
-       outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP);
-
-       /* Initialize XMT */
-       outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar);
-       lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
-       lp->tx_last = 0;
-
-       /* Check for the i82595TX and i82595FX */
-       old8 = inb(ioaddr + 8);
-       outb(~old8, ioaddr + 8);
-
-       if ((temp_reg = inb(ioaddr + 8)) == old8) {
-               if (net_debug > 3)
-                       printk(KERN_DEBUG "i82595 detected!\n");
-               lp->version = LAN595;
-       }
-       else {
-               lp->version = LAN595TX;
-               outb(old8, ioaddr + 8);
-               old9 = inb(ioaddr + 9);
-
-               if (irqMask==ee_FX_INT2IRQ) {
-                       if (net_debug > 3) {
-                               printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
-                               printk(KERN_DEBUG "i82595FX detected!\n");
-                       }
-                       lp->version = LAN595FX;
-                       outb(old9, ioaddr + 9);
-                       if (dev->if_port != TPE) {      /* Hopefully, this will fix the
-                                                       problem of using Pentiums and
-                                                       pro/10 w/ BNC. */
-                               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-                               temp_reg = inb(ioaddr + REG13);
-                               /* disable the full duplex mode since it is not
-                               applicable with the 10Base2 cable. */
-                               outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
-                               eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
-                       }
-               }
-               else if (net_debug > 3) {
-                       printk(KERN_DEBUG "temp_reg: %#x  ~old9: %#x\n",temp_reg,((~old9)&0xff));
-                       printk(KERN_DEBUG "i82595TX detected!\n");
-               }
-       }
-
-       eepro_sel_reset(ioaddr);
-
-       netif_start_queue(dev);
-
-       if (net_debug > 3)
-               printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
-
-       /* enabling rx */
-       eepro_en_rx(ioaddr);
-
-       return 0;
-}
-
-static void eepro_tx_timeout (struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       /* if (net_debug > 1) */
-       printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
-               "network cable problem");
-       /* This is not a duplicate. One message for the console,
-          one for the log file  */
-       printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
-               "network cable problem");
-       eepro_complete_selreset(ioaddr);
-}
-
-
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
-                                    struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       unsigned long flags;
-       int ioaddr = dev->base_addr;
-       short length = skb->len;
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG  "%s: entering eepro_send_packet routine.\n", dev->name);
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-       netif_stop_queue (dev);
-
-       eepro_dis_int(ioaddr);
-       spin_lock_irqsave(&lp->lock, flags);
-
-       {
-               unsigned char *buf = skb->data;
-
-               if (hardware_send_packet(dev, buf, length))
-                       /* we won't wake queue here because we're out of space */
-                       dev->stats.tx_dropped++;
-               else {
-                       dev->stats.tx_bytes+=skb->len;
-                       netif_wake_queue(dev);
-               }
-
-       }
-
-       dev_kfree_skb (skb);
-
-       /* You might need to clean up and record Tx statistics here. */
-       /* dev->stats.tx_aborted_errors++; */
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
-
-       eepro_en_int(ioaddr);
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       return NETDEV_TX_OK;
-}
-
-
-/*     The typical workload of the driver:
-       Handle the network interface interrupts. */
-
-static irqreturn_t
-eepro_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct eepro_local *lp;
-       int ioaddr, status, boguscount = 20;
-       int handled = 0;
-
-       lp = netdev_priv(dev);
-
-        spin_lock(&lp->lock);
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);
-
-       ioaddr = dev->base_addr;
-
-       while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--))
-       {
-               handled = 1;
-               if (status & RX_INT) {
-                       if (net_debug > 4)
-                               printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);
-
-                       eepro_dis_int(ioaddr);
-
-                       /* Get the received packets */
-                       eepro_ack_rx(ioaddr);
-                       eepro_rx(dev);
-
-                       eepro_en_int(ioaddr);
-               }
-               if (status & TX_INT) {
-                       if (net_debug > 4)
-                               printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
-
-
-                       eepro_dis_int(ioaddr);
-
-                       /* Process the status of transmitted packets */
-                       eepro_ack_tx(ioaddr);
-                       eepro_transmit_interrupt(dev);
-
-                       eepro_en_int(ioaddr);
-               }
-       }
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
-
-       spin_unlock(&lp->lock);
-       return IRQ_RETVAL(handled);
-}
-
-static int eepro_close(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       short temp_reg;
-
-       netif_stop_queue(dev);
-
-       eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
-       /* Disable the physical interrupt line. */
-       temp_reg = inb(ioaddr + REG1);
-       outb(temp_reg & 0x7f, ioaddr + REG1);
-
-       eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-       /* Flush the Tx and disable Rx. */
-       outb(STOP_RCV_CMD, ioaddr);
-       lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
-       lp->tx_last = 0;
-
-       /* Mask all the interrupts. */
-       eepro_dis_int(ioaddr);
-
-       /* clear all interrupts */
-       eepro_clear_int(ioaddr);
-
-       /* Reset the 82595 */
-       eepro_reset(ioaddr);
-
-       /* release the interrupt */
-       free_irq(dev->irq, dev);
-
-       /* Update the statistics here. What statistics? */
-
-       return 0;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       unsigned short mode;
-       struct netdev_hw_addr *ha;
-       int mc_count = netdev_mc_count(dev);
-
-       if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
-       {
-               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-               mode = inb(ioaddr + REG2);
-               outb(mode | PRMSC_Mode, ioaddr + REG2);
-               mode = inb(ioaddr + REG3);
-               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-       }
-
-       else if (mc_count == 0)
-       {
-               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-               mode = inb(ioaddr + REG2);
-               outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
-               mode = inb(ioaddr + REG3);
-               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-       }
-
-       else
-       {
-               unsigned short status, *eaddrs;
-               int i, boguscount = 0;
-
-               /* Disable RX and TX interrupts.  Necessary to avoid
-                  corruption of the HOST_ADDRESS_REG by interrupt
-                  service routines. */
-               eepro_dis_int(ioaddr);
-
-               eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-               mode = inb(ioaddr + REG2);
-               outb(mode | Multi_IA, ioaddr + REG2);
-               mode = inb(ioaddr + REG3);
-               outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-               eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-               outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
-               outw(MC_SETUP, ioaddr + IO_PORT);
-               outw(0, ioaddr + IO_PORT);
-               outw(0, ioaddr + IO_PORT);
-               outw(6 * (mc_count + 1), ioaddr + IO_PORT);
-
-               netdev_for_each_mc_addr(ha, dev) {
-                       eaddrs = (unsigned short *) ha->addr;
-                       outw(*eaddrs++, ioaddr + IO_PORT);
-                       outw(*eaddrs++, ioaddr + IO_PORT);
-                       outw(*eaddrs++, ioaddr + IO_PORT);
-               }
-
-               eaddrs = (unsigned short *) dev->dev_addr;
-               outw(eaddrs[0], ioaddr + IO_PORT);
-               outw(eaddrs[1], ioaddr + IO_PORT);
-               outw(eaddrs[2], ioaddr + IO_PORT);
-               outw(lp->tx_end, ioaddr + lp->xmt_bar);
-               outb(MC_SETUP, ioaddr);
-
-               /* Update the transmit queue */
-               i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
-
-               if (lp->tx_start != lp->tx_end)
-               {
-                       /* update the next address and the chain bit in the
-                          last packet */
-                       outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
-                       outw(i, ioaddr + IO_PORT);
-                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
-                       status = inw(ioaddr + IO_PORT);
-                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-                       lp->tx_end = i ;
-               }
-               else {
-                       lp->tx_start = lp->tx_end = i ;
-               }
-
-               /* Acknowledge that the MC setup is done */
-               do { /* We should be doing this in the eepro_interrupt()! */
-                       SLOW_DOWN;
-                       SLOW_DOWN;
-                       if (inb(ioaddr + STATUS_REG) & 0x08)
-                       {
-                               i = inb(ioaddr);
-                               outb(0x08, ioaddr + STATUS_REG);
-
-                               if (i & 0x20) { /* command ABORTed */
-                                       printk(KERN_NOTICE "%s: multicast setup failed.\n",
-                                               dev->name);
-                                       break;
-                               } else if ((i & 0x0f) == 0x03)  { /* MC-Done */
-                                       printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
-                                               dev->name, mc_count,
-                                               mc_count > 1 ? "es":"");
-                                       break;
-                               }
-                       }
-               } while (++boguscount < 100);
-
-               /* Re-enable RX and TX interrupts */
-               eepro_en_int(ioaddr);
-       }
-       if (lp->eepro == LAN595FX_10ISA) {
-               eepro_complete_selreset(ioaddr);
-       }
-       else
-               eepro_en_rx(ioaddr);
-}
-
-/* The horrible routine to read a word from the serial EEPROM. */
-/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
-
-/* The delay between EEPROM clock transitions. */
-#define eeprom_delay() { udelay(40); }
-#define EE_READ_CMD (6 << 6)
-
-static int
-read_eeprom(int ioaddr, int location, struct net_device *dev)
-{
-       int i;
-       unsigned short retval = 0;
-       struct eepro_local *lp = netdev_priv(dev);
-       short ee_addr = ioaddr + lp->eeprom_reg;
-       int read_cmd = location | EE_READ_CMD;
-       short ctrl_val = EECS ;
-
-       /* XXXX - black magic */
-               eepro_sw2bank1(ioaddr);
-               outb(0x00, ioaddr + STATUS_REG);
-       /* XXXX - black magic */
-
-       eepro_sw2bank2(ioaddr);
-       outb(ctrl_val, ee_addr);
-
-       /* Shift the read command bits out. */
-       for (i = 8; i >= 0; i--) {
-               short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
-                       : ctrl_val;
-               outb(outval, ee_addr);
-               outb(outval | EESK, ee_addr);   /* EEPROM clock tick. */
-               eeprom_delay();
-               outb(outval, ee_addr);  /* Finish EEPROM a clock tick. */
-               eeprom_delay();
-       }
-       outb(ctrl_val, ee_addr);
-
-       for (i = 16; i > 0; i--) {
-               outb(ctrl_val | EESK, ee_addr);  eeprom_delay();
-               retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
-               outb(ctrl_val, ee_addr);  eeprom_delay();
-       }
-
-       /* Terminate the EEPROM access. */
-       ctrl_val &= ~EECS;
-       outb(ctrl_val | EESK, ee_addr);
-       eeprom_delay();
-       outb(ctrl_val, ee_addr);
-       eeprom_delay();
-       eepro_sw2bank0(ioaddr);
-       return retval;
-}
-
-static int
-hardware_send_packet(struct net_device *dev, void *buf, short length)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       unsigned status, tx_available, last, end;
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
-
-       /* determine how much of the transmit buffer space is available */
-       if (lp->tx_end > lp->tx_start)
-               tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
-       else if (lp->tx_end < lp->tx_start)
-               tx_available = lp->tx_start - lp->tx_end;
-       else tx_available = lp->xmt_ram;
-
-       if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
-               /* No space available ??? */
-               return 1;
-               }
-
-               last = lp->tx_end;
-               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-
-       if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */
-               if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) {
-                               /* Arrrr!!!, must keep the xmt header together,
-                               several days were lost to chase this one down. */
-                       last = lp->xmt_lower_limit;
-                               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-                       }
-               else end = lp->xmt_lower_limit + (end -
-                                               lp->xmt_upper_limit + 2);
-               }
-
-               outw(last, ioaddr + HOST_ADDRESS_REG);
-               outw(XMT_CMD, ioaddr + IO_PORT);
-               outw(0, ioaddr + IO_PORT);
-               outw(end, ioaddr + IO_PORT);
-               outw(length, ioaddr + IO_PORT);
-
-               if (lp->version == LAN595)
-                       outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
-               else {  /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
-                       unsigned short temp = inb(ioaddr + INT_MASK_REG);
-                       outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
-                       outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
-                       outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
-               }
-
-               /* A dummy read to flush the DRAM write pipeline */
-               status = inw(ioaddr + IO_PORT);
-
-               if (lp->tx_start == lp->tx_end) {
-               outw(last, ioaddr + lp->xmt_bar);
-                       outb(XMT_CMD, ioaddr);
-                       lp->tx_start = last;   /* I don't like to change tx_start here */
-               }
-               else {
-                       /* update the next address and the chain bit in the
-                       last packet */
-
-                       if (lp->tx_end != last) {
-                               outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
-                               outw(last, ioaddr + IO_PORT);
-                       }
-
-                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
-                       status = inw(ioaddr + IO_PORT);
-                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
-                       /* Continue the transmit command */
-                       outb(RESUME_XMT_CMD, ioaddr);
-               }
-
-               lp->tx_last = last;
-               lp->tx_end = end;
-
-               if (net_debug > 5)
-                       printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
-
-       return 0;
-}
-
-static void
-eepro_rx(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       short boguscount = 20;
-       short rcv_car = lp->rx_start;
-       unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
-
-       /* Set the read pointer to the start of the RCV */
-       outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
-
-       rcv_event = inw(ioaddr + IO_PORT);
-
-       while (rcv_event == RCV_DONE) {
-
-               rcv_status = inw(ioaddr + IO_PORT);
-               rcv_next_frame = inw(ioaddr + IO_PORT);
-               rcv_size = inw(ioaddr + IO_PORT);
-
-               if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
-
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       dev->stats.rx_bytes+=rcv_size;
-                       rcv_size &= 0x3fff;
-                       skb = netdev_alloc_skb(dev, rcv_size + 5);
-                       if (skb == NULL) {
-                               printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-                               dev->stats.rx_dropped++;
-                               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
-                               lp->rx_start = rcv_next_frame;
-                               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-
-                               break;
-                       }
-                       skb_reserve(skb,2);
-
-                       if (lp->version == LAN595)
-                               insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
-                       else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
-                               unsigned short temp = inb(ioaddr + INT_MASK_REG);
-                               outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
-                               insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size),
-                                       (rcv_size + 3) >> 2);
-                               outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
-                       }
-
-                       skb->protocol = eth_type_trans(skb,dev);
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-               }
-
-               else { /* Not sure will ever reach here,
-                       I set the 595 to discard bad received frames */
-                       dev->stats.rx_errors++;
-
-                       if (rcv_status & 0x0100)
-                               dev->stats.rx_over_errors++;
-
-                       else if (rcv_status & 0x0400)
-                               dev->stats.rx_frame_errors++;
-
-                       else if (rcv_status & 0x0800)
-                               dev->stats.rx_crc_errors++;
-
-                       printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
-                               dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
-               }
-
-               if (rcv_status & 0x1000)
-                       dev->stats.rx_length_errors++;
-
-               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
-               lp->rx_start = rcv_next_frame;
-
-               if (--boguscount == 0)
-                       break;
-
-               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-               rcv_event = inw(ioaddr + IO_PORT);
-
-       }
-       if (rcv_car == 0)
-               rcv_car = lp->rcv_upper_limit | 0xff;
-
-       outw(rcv_car - 1, ioaddr + RCV_STOP);
-
-       if (net_debug > 5)
-               printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
-}
-
-static void
-eepro_transmit_interrupt(struct net_device *dev)
-{
-       struct eepro_local *lp = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       short boguscount = 25;
-       short xmt_status;
-
-       while ((lp->tx_start != lp->tx_end) && boguscount--) {
-
-               outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
-               xmt_status = inw(ioaddr+IO_PORT);
-
-               if (!(xmt_status & TX_DONE_BIT))
-                               break;
-
-               xmt_status = inw(ioaddr+IO_PORT);
-               lp->tx_start = inw(ioaddr+IO_PORT);
-
-               netif_wake_queue (dev);
-
-               if (xmt_status & TX_OK)
-                       dev->stats.tx_packets++;
-               else {
-                       dev->stats.tx_errors++;
-                       if (xmt_status & 0x0400) {
-                               dev->stats.tx_carrier_errors++;
-                               printk(KERN_DEBUG "%s: carrier error\n",
-                                       dev->name);
-                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
-                                       dev->name, xmt_status);
-                       }
-                       else {
-                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
-                                       dev->name, xmt_status);
-                               printk(KERN_DEBUG "%s: XMT status = %#x\n",
-                                       dev->name, xmt_status);
-                       }
-               }
-               if (xmt_status & 0x000f) {
-                       dev->stats.collisions += (xmt_status & 0x000f);
-               }
-
-               if ((xmt_status & 0x0040) == 0x0) {
-                       dev->stats.tx_heartbeat_errors++;
-               }
-       }
-}
-
-static int eepro_ethtool_get_settings(struct net_device *dev,
-                                       struct ethtool_cmd *cmd)
-{
-       struct eepro_local      *lp = netdev_priv(dev);
-
-       cmd->supported =        SUPPORTED_10baseT_Half |
-                               SUPPORTED_10baseT_Full |
-                               SUPPORTED_Autoneg;
-       cmd->advertising =      ADVERTISED_10baseT_Half |
-                               ADVERTISED_10baseT_Full |
-                               ADVERTISED_Autoneg;
-
-       if (GetBit(lp->word[5], ee_PortTPE)) {
-               cmd->supported |= SUPPORTED_TP;
-               cmd->advertising |= ADVERTISED_TP;
-       }
-       if (GetBit(lp->word[5], ee_PortBNC)) {
-               cmd->supported |= SUPPORTED_BNC;
-               cmd->advertising |= ADVERTISED_BNC;
-       }
-       if (GetBit(lp->word[5], ee_PortAUI)) {
-               cmd->supported |= SUPPORTED_AUI;
-               cmd->advertising |= ADVERTISED_AUI;
-       }
-
-       ethtool_cmd_speed_set(cmd, SPEED_10);
-
-       if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
-               cmd->duplex = DUPLEX_FULL;
-       }
-       else {
-               cmd->duplex = DUPLEX_HALF;
-       }
-
-       cmd->port = dev->if_port;
-       cmd->phy_address = dev->base_addr;
-       cmd->transceiver = XCVR_INTERNAL;
-
-       if (lp->word[0] & ee_AutoNeg) {
-               cmd->autoneg = 1;
-       }
-
-       return 0;
-}
-
-static void eepro_ethtool_get_drvinfo(struct net_device *dev,
-                                       struct ethtool_drvinfo *drvinfo)
-{
-       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
-       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
-       snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
-               "ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops = {
-       .get_settings   = eepro_ethtool_get_settings,
-       .get_drvinfo    = eepro_ethtool_get_drvinfo,
-};
-
-#ifdef MODULE
-
-#define MAX_EEPRO 8
-static struct net_device *dev_eepro[MAX_EEPRO];
-
-static int io[MAX_EEPRO] = {
-  [0 ... MAX_EEPRO-1] = -1
-};
-static int irq[MAX_EEPRO];
-static int mem[MAX_EEPRO] = {  /* Size of the rx buffer in KB */
-  [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
-};
-static int autodetect;
-
-static int n_eepro;
-/* For linux 2.1.xx */
-
-MODULE_AUTHOR("Pascal Dupuis and others");
-MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
-MODULE_LICENSE("GPL");
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param(autodetect, int, 0);
-MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
-MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
-MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
-
-int __init init_module(void)
-{
-       struct net_device *dev;
-       int i;
-       if (io[0] == -1 && autodetect == 0) {
-               printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n");
-               printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n");
-               return -ENODEV;
-       }
-       else if (autodetect) {
-               /* if autodetect is set then we must force detection */
-               for (i = 0; i < MAX_EEPRO; i++) {
-                       io[i] = 0;
-               }
-
-               printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
-       }
-
-       for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
-               dev = alloc_etherdev(sizeof(struct eepro_local));
-               if (!dev)
-                       break;
-
-               dev->mem_end = mem[i];
-               dev->base_addr = io[i];
-               dev->irq = irq[i];
-
-               if (do_eepro_probe(dev) == 0) {
-                       dev_eepro[n_eepro++] = dev;
-                       continue;
-               }
-               free_netdev(dev);
-               break;
-       }
-
-       if (n_eepro)
-               printk(KERN_INFO "%s", version);
-
-       return n_eepro ? 0 : -ENODEV;
-}
-
-void __exit
-cleanup_module(void)
-{
-       int i;
-
-       for (i=0; i<n_eepro; i++) {
-               struct net_device *dev = dev_eepro[i];
-               unregister_netdev(dev);
-               release_region(dev->base_addr, EEPRO_IO_EXTENT);
-               free_netdev(dev);
-       }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c
deleted file mode 100644 (file)
index 7a6a2f0..0000000
+++ /dev/null
@@ -1,1661 +0,0 @@
-/* Intel EtherExpress 16 device driver for Linux
- *
- * Written by John Sullivan, 1995
- *  based on original code by Donald Becker, with changes by
- *  Alan Cox and Pauline Middelink.
- *
- * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
- *
- * Many modifications, and currently maintained, by
- *  Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE  Alan Cox <alan@lxorguk.ukuu.org.uk>
- * Added MCA support Adam Fritzler (now deleted)
- *
- * Note - this driver is experimental still - it has problems on faster
- * machines. Someone needs to sit down and go through it line by line with
- * a databook...
- */
-
-/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
- * design using the i82586 Ethernet coprocessor.  It bears no relationship,
- * as far as I know, to the similarly-named "EtherExpress Pro" range.
- *
- * Historically, Linux support for these cards has been very bad.  However,
- * things seem to be getting better slowly.
- */
-
-/* If your card is confused about what sort of interface it has (eg it
- * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
- * or 'SOFTSET /LISA' from DOS seems to help.
- */
-
-/* Here's the scoop on memory mapping.
- *
- * There are three ways to access EtherExpress card memory: either using the
- * shared-memory mapping, or using PIO through the dataport, or using PIO
- * through the "shadow memory" ports.
- *
- * The shadow memory system works by having the card map some of its memory
- * as follows:
- *
- * (the low five bits of the SMPTR are ignored)
- *
- *  base+0x4000..400f      memory at SMPTR+0..15
- *  base+0x8000..800f      memory at SMPTR+16..31
- *  base+0xc000..c007      dubious stuff (memory at SMPTR+16..23 apparently)
- *  base+0xc008..c00f      memory at 0x0008..0x000f
- *
- * This last set (the one at c008) is particularly handy because the SCB
- * lives at 0x0008.  So that set of ports gives us easy random access to data
- * in the SCB without having to mess around setting up pointers and the like.
- * We always use this method to access the SCB (via the scb_xx() functions).
- *
- * Dataport access works by aiming the appropriate (read or write) pointer
- * at the first address you're interested in, and then reading or writing from
- * the dataport.  The pointers auto-increment after each transfer.  We use
- * this for data transfer.
- *
- * We don't use the shared-memory system because it allegedly doesn't work on
- * all cards, and because it's a bit more prone to go wrong (it's one more
- * thing to configure...).
- */
-
-/* Known bugs:
- *
- * - The card seems to want to give us two interrupts every time something
- *   happens, where just one would be better.
- */
-
-/*
- *
- * Note by Zoltan Szilagyi 10-12-96:
- *
- * I've succeeded in eliminating the "CU wedged" messages, and hence the
- * lockups, which were only occurring with cards running in 8-bit mode ("force
- * 8-bit operation" in Intel's SoftSet utility). This version of the driver
- * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
- * CU before submitting a packet for transmission, and then restarts it as soon
- * as the process of handing the packet is complete. This is definitely an
- * unnecessary slowdown if the card is running in 16-bit mode; therefore one
- * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
- * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
- * ftp's, which is significantly better than I get in DOS, so the overhead of
- * stopping and restarting the CU with each transmit is not prohibitive in
- * practice.
- *
- * Update by David Woodhouse 11/5/99:
- *
- * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
- * I assume that this is because 16-bit accesses are actually handled as two
- * 8-bit accesses.
- */
-
-#ifdef __alpha__
-#define LOCKUP16 1
-#endif
-#ifndef LOCKUP16
-#define LOCKUP16 0
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifndef NET_DEBUG
-#define NET_DEBUG 4
-#endif
-
-#include "eexpress.h"
-
-#define EEXP_IO_EXTENT  16
-
-/*
- * Private data declarations
- */
-
-struct net_local
-{
-       unsigned long last_tx;       /* jiffies when last transmit started */
-       unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
-       unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
-       unsigned short rx_last;      /* last rx buf */
-       unsigned short rx_ptr;       /* first rx buf to look at */
-       unsigned short tx_head;      /* next free tx buf */
-       unsigned short tx_reap;      /* first in-use tx buf */
-       unsigned short tx_tail;      /* previous tx buf to tx_head */
-       unsigned short tx_link;      /* last known-executing tx buf */
-       unsigned short last_tx_restart;   /* set to tx_link when we
-                                            restart the CU */
-       unsigned char started;
-       unsigned short rx_buf_start;
-       unsigned short rx_buf_end;
-       unsigned short num_tx_bufs;
-       unsigned short num_rx_bufs;
-       unsigned char width;         /* 0 for 16bit, 1 for 8bit */
-       unsigned char was_promisc;
-       unsigned char old_mc_count;
-       spinlock_t lock;
-};
-
-/* This is the code and data that is downloaded to the EtherExpress card's
- * memory at boot time.
- */
-
-static unsigned short start_code[] = {
-/* 0x0000 */
-       0x0001,                 /* ISCP: busy - cleared after reset */
-       0x0008,0x0000,0x0000,   /* offset,address (lo,hi) of SCB */
-
-       0x0000,0x0000,          /* SCB: status, commands */
-       0x0000,0x0000,          /* links to first command block,
-                                  first receive descriptor */
-       0x0000,0x0000,          /* CRC error, alignment error counts */
-       0x0000,0x0000,          /* out of resources, overrun error counts */
-
-       0x0000,0x0000,          /* pad */
-       0x0000,0x0000,
-
-/* 0x20 -- start of 82586 CU program */
-#define CONF_LINK 0x20
-       0x0000,Cmd_Config,
-       0x0032,                 /* link to next command */
-       0x080c,                 /* 12 bytes follow : fifo threshold=8 */
-       0x2e40,                 /* don't rx bad frames
-                                * SRDY/ARDY => ext. sync. : preamble len=8
-                                * take addresses from data buffers
-                                * 6 bytes/address
-                                */
-       0x6000,                 /* default backoff method & priority
-                                * interframe spacing = 0x60 */
-       0xf200,                 /* slot time=0x200
-                                * max collision retry = 0xf */
-#define CONF_PROMISC  0x2e
-       0x0000,                 /* no HDLC : normal CRC : enable broadcast
-                                * disable promiscuous/multicast modes */
-       0x003c,                 /* minimum frame length = 60 octets) */
-
-       0x0000,Cmd_SetAddr,
-       0x003e,                 /* link to next command */
-#define CONF_HWADDR  0x38
-       0x0000,0x0000,0x0000,   /* hardware address placed here */
-
-       0x0000,Cmd_MCast,
-       0x0076,                 /* link to next command */
-#define CONF_NR_MULTICAST 0x44
-       0x0000,                 /* number of bytes in multicast address(es) */
-#define CONF_MULTICAST 0x46
-       0x0000, 0x0000, 0x0000, /* some addresses */
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000,
-
-#define CONF_DIAG_RESULT  0x76
-       0x0000, Cmd_Diag,
-       0x007c,                 /* link to next command */
-
-       0x0000,Cmd_TDR|Cmd_INT,
-       0x0084,
-#define CONF_TDR_RESULT  0x82
-       0x0000,
-
-       0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
-       0x0084                  /* dummy link */
-};
-
-/* maps irq number to EtherExpress magic value */
-static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
-
-/*
- * Prototypes for Linux interface
- */
-
-static int eexp_open(struct net_device *dev);
-static int eexp_close(struct net_device *dev);
-static void eexp_timeout(struct net_device *dev);
-static netdev_tx_t eexp_xmit(struct sk_buff *buf,
-                            struct net_device *dev);
-
-static irqreturn_t eexp_irq(int irq, void *dev_addr);
-static void eexp_set_multicast(struct net_device *dev);
-
-/*
- * Prototypes for hardware access functions
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev);
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
-                      unsigned short len);
-static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
-                                        unsigned char location);
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev);
-static void eexp_hw_txrestart(struct net_device *dev);
-
-static void eexp_hw_txinit    (struct net_device *dev);
-static void eexp_hw_rxinit    (struct net_device *dev);
-
-static void eexp_hw_init586   (struct net_device *dev);
-static void eexp_setup_filter (struct net_device *dev);
-
-static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};
-enum eexp_iftype {AUI=0, BNC=1, TPE=2};
-
-#define STARTED_RU      2
-#define STARTED_CU      1
-
-/*
- * Primitive hardware access functions.
- */
-
-static inline unsigned short scb_status(struct net_device *dev)
-{
-       return inw(dev->base_addr + 0xc008);
-}
-
-static inline unsigned short scb_rdcmd(struct net_device *dev)
-{
-       return inw(dev->base_addr + 0xc00a);
-}
-
-static inline void scb_command(struct net_device *dev, unsigned short cmd)
-{
-       outw(cmd, dev->base_addr + 0xc00a);
-}
-
-static inline void scb_wrcbl(struct net_device *dev, unsigned short val)
-{
-       outw(val, dev->base_addr + 0xc00c);
-}
-
-static inline void scb_wrrfa(struct net_device *dev, unsigned short val)
-{
-       outw(val, dev->base_addr + 0xc00e);
-}
-
-static inline void set_loopback(struct net_device *dev)
-{
-       outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);
-}
-
-static inline void clear_loopback(struct net_device *dev)
-{
-       outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
-}
-
-static inline unsigned short int SHADOW(short int addr)
-{
-       addr &= 0x1f;
-       if (addr > 0xf) addr += 0x3ff0;
-       return addr + 0x4000;
-}
-
-/*
- * Linux interface
- */
-
-/*
- * checks for presence of EtherExpress card
- */
-
-static int __init do_express_probe(struct net_device *dev)
-{
-       unsigned short *port;
-       static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
-       unsigned short ioaddr = dev->base_addr;
-       int dev_irq = dev->irq;
-       int err;
-
-       dev->if_port = 0xff; /* not set */
-
-       if (ioaddr&0xfe00) {
-               if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress"))
-                       return -EBUSY;
-               err = eexp_hw_probe(dev,ioaddr);
-               release_region(ioaddr, EEXP_IO_EXTENT);
-               return err;
-       } else if (ioaddr)
-               return -ENXIO;
-
-       for (port=&ports[0] ; *port ; port++ )
-       {
-               unsigned short sum = 0;
-               int i;
-               if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress"))
-                       continue;
-               for ( i=0 ; i<4 ; i++ )
-               {
-                       unsigned short t;
-                       t = inb(*port + ID_PORT);
-                       sum |= (t>>4) << ((t & 0x03)<<2);
-               }
-               if (sum==0xbaba && !eexp_hw_probe(dev,*port)) {
-                       release_region(*port, EEXP_IO_EXTENT);
-                       return 0;
-               }
-               release_region(*port, EEXP_IO_EXTENT);
-               dev->irq = dev_irq;
-       }
-       return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init express_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-
-       err = do_express_probe(dev);
-       if (!err)
-               return dev;
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif
-
-/*
- * open and initialize the adapter, ready for use
- */
-
-static int eexp_open(struct net_device *dev)
-{
-       int ret;
-       unsigned short ioaddr = dev->base_addr;
-       struct net_local *lp = netdev_priv(dev);
-
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
-#endif
-
-       if (!dev->irq || !irqrmap[dev->irq])
-               return -ENXIO;
-
-       ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev);
-       if (ret)
-               return ret;
-
-       if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr);
-               goto err_out1;
-       }
-       if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr+0x4000);
-               goto err_out2;
-       }
-       if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr+0x8000);
-               goto err_out3;
-       }
-       if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-               printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-                       , ioaddr+0xc000);
-               goto err_out4;
-       }
-
-       if (lp->width) {
-               printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
-               outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
-       }
-
-       eexp_hw_init586(dev);
-       netif_start_queue(dev);
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
-#endif
-       return 0;
-
-       err_out4:
-               release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
-       err_out3:
-               release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
-       err_out2:
-               release_region(ioaddr, EEXP_IO_EXTENT);
-       err_out1:
-               free_irq(dev->irq, dev);
-               return -EBUSY;
-}
-
-/*
- * close and disable the interface, leaving the 586 in reset.
- */
-
-static int eexp_close(struct net_device *dev)
-{
-       unsigned short ioaddr = dev->base_addr;
-       struct net_local *lp = netdev_priv(dev);
-
-       int irq = dev->irq;
-
-       netif_stop_queue(dev);
-
-       outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-       lp->started = 0;
-       scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
-       outb(0,ioaddr+SIGNAL_CA);
-       free_irq(irq,dev);
-       outb(i586_RST,ioaddr+EEPROM_Ctrl);
-       release_region(ioaddr, EEXP_IO_EXTENT);
-       release_region(ioaddr+0x4000, 16);
-       release_region(ioaddr+0x8000, 16);
-       release_region(ioaddr+0xc000, 16);
-
-       return 0;
-}
-
-/*
- * This gets called when a higher level thinks we are broken.  Check that
- * nothing has become jammed in the CU.
- */
-
-static void unstick_cu(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-
-       if (lp->started)
-       {
-               if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
-               {
-                       if (lp->tx_link==lp->last_tx_restart)
-                       {
-                               unsigned short boguscount=200,rsst;
-                               printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
-                                      dev->name, scb_status(dev));
-                               eexp_hw_txinit(dev);
-                               lp->last_tx_restart = 0;
-                               scb_wrcbl(dev, lp->tx_link);
-                               scb_command(dev, SCB_CUstart);
-                               outb(0,ioaddr+SIGNAL_CA);
-                               while (!SCB_complete(rsst=scb_status(dev)))
-                               {
-                                       if (!--boguscount)
-                                       {
-                                               boguscount=200;
-                                               printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
-                                                      dev->name,rsst);
-                                               scb_wrcbl(dev, lp->tx_link);
-                                               scb_command(dev, SCB_CUstart);
-                                               outb(0,ioaddr+SIGNAL_CA);
-                                       }
-                               }
-                               netif_wake_queue(dev);
-                       }
-                       else
-                       {
-                               unsigned short status = scb_status(dev);
-                               if (SCB_CUdead(status))
-                               {
-                                       unsigned short txstatus = eexp_hw_lasttxstat(dev);
-                                       printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
-                                              dev->name, status, txstatus);
-                                       eexp_hw_txrestart(dev);
-                               }
-                               else
-                               {
-                                       unsigned short txstatus = eexp_hw_lasttxstat(dev);
-                                       if (netif_queue_stopped(dev) && !txstatus)
-                                       {
-                                               printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
-                                                      dev->name,status,txstatus);
-                                               eexp_hw_init586(dev);
-                                               netif_wake_queue(dev);
-                                       }
-                                       else
-                                       {
-                                               printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
-                                       }
-                               }
-                       }
-               }
-       }
-       else
-       {
-               if (time_after(jiffies, lp->init_time + 10))
-               {
-                       unsigned short status = scb_status(dev);
-                       printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
-                              dev->name, status);
-                       eexp_hw_init586(dev);
-                       netif_wake_queue(dev);
-               }
-       }
-}
-
-static void eexp_timeout(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-#ifdef CONFIG_SMP
-       unsigned long flags;
-#endif
-       int status;
-
-       disable_irq(dev->irq);
-
-       /*
-        *      Best would be to use synchronize_irq(); spin_lock() here
-        *      lets make it work first..
-        */
-
-#ifdef CONFIG_SMP
-       spin_lock_irqsave(&lp->lock, flags);
-#endif
-
-       status = scb_status(dev);
-       unstick_cu(dev);
-       printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
-              (SCB_complete(status)?"lost interrupt":
-               "board on fire"));
-       dev->stats.tx_errors++;
-       lp->last_tx = jiffies;
-       if (!SCB_complete(status)) {
-               scb_command(dev, SCB_CUabort);
-               outb(0,dev->base_addr+SIGNAL_CA);
-       }
-       netif_wake_queue(dev);
-#ifdef CONFIG_SMP
-       spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-}
-
-/*
- * Called to transmit a packet, or to allow us to right ourselves
- * if the kernel thinks we've died.
- */
-static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev)
-{
-       short length = buf->len;
-#ifdef CONFIG_SMP
-       struct net_local *lp = netdev_priv(dev);
-       unsigned long flags;
-#endif
-
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
-#endif
-
-       if (buf->len < ETH_ZLEN) {
-               if (skb_padto(buf, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-
-       disable_irq(dev->irq);
-
-       /*
-        *      Best would be to use synchronize_irq(); spin_lock() here
-        *      lets make it work first..
-        */
-
-#ifdef CONFIG_SMP
-       spin_lock_irqsave(&lp->lock, flags);
-#endif
-
-       {
-               unsigned short *data = (unsigned short *)buf->data;
-
-               dev->stats.tx_bytes += length;
-
-               eexp_hw_tx_pio(dev,data,length);
-       }
-       dev_kfree_skb(buf);
-#ifdef CONFIG_SMP
-       spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-       enable_irq(dev->irq);
-       return NETDEV_TX_OK;
-}
-
-/*
- * Handle an EtherExpress interrupt
- * If we've finished initializing, start the RU and CU up.
- * If we've already started, reap tx buffers, handle any received packets,
- * check to make sure we've not become wedged.
- */
-
-static unsigned short eexp_start_irq(struct net_device *dev,
-                                    unsigned short status)
-{
-       unsigned short ack_cmd = SCB_ack(status);
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-       if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
-               short diag_status, tdr_status;
-               while (SCB_CUstat(status)==2)
-                       status = scb_status(dev);
-#if NET_DEBUG > 4
-               printk("%s: CU went non-active (status %04x)\n",
-                      dev->name, status);
-#endif
-
-               outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
-               diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
-               if (diag_status & 1<<11) {
-                       printk(KERN_WARNING "%s: 82586 failed self-test\n",
-                              dev->name);
-               } else if (!(diag_status & 1<<13)) {
-                       printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
-               }
-
-               outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);
-               tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
-               if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
-                       printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
-               }
-               else if (tdr_status & TDR_XCVRPROBLEM) {
-                       printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
-               }
-               else if (tdr_status & TDR_LINKOK) {
-#if NET_DEBUG > 4
-                       printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
-#endif
-               } else {
-                       printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
-                              tdr_status);
-               }
-
-               lp->started |= STARTED_CU;
-               scb_wrcbl(dev, lp->tx_link);
-               /* if the RU isn't running, start it now */
-               if (!(lp->started & STARTED_RU)) {
-                       ack_cmd |= SCB_RUstart;
-                       scb_wrrfa(dev, lp->rx_buf_start);
-                       lp->rx_ptr = lp->rx_buf_start;
-                       lp->started |= STARTED_RU;
-               }
-               ack_cmd |= SCB_CUstart | 0x2000;
-       }
-
-       if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
-               lp->started|=STARTED_RU;
-
-       return ack_cmd;
-}
-
-static void eexp_cmd_clear(struct net_device *dev)
-{
-       unsigned long int oldtime = jiffies;
-       while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
-       if (scb_rdcmd(dev)) {
-               printk("%s: command didn't clear\n", dev->name);
-       }
-}
-
-static irqreturn_t eexp_irq(int dummy, void *dev_info)
-{
-       struct net_device *dev = dev_info;
-       struct net_local *lp;
-       unsigned short ioaddr,status,ack_cmd;
-       unsigned short old_read_ptr, old_write_ptr;
-
-       lp = netdev_priv(dev);
-       ioaddr = dev->base_addr;
-
-       spin_lock(&lp->lock);
-
-       old_read_ptr = inw(ioaddr+READ_PTR);
-       old_write_ptr = inw(ioaddr+WRITE_PTR);
-
-       outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-       status = scb_status(dev);
-
-#if NET_DEBUG > 4
-       printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
-#endif
-
-       if (lp->started == (STARTED_CU | STARTED_RU)) {
-
-               do {
-                       eexp_cmd_clear(dev);
-
-                       ack_cmd = SCB_ack(status);
-                       scb_command(dev, ack_cmd);
-                       outb(0,ioaddr+SIGNAL_CA);
-
-                       eexp_cmd_clear(dev);
-
-                       if (SCB_complete(status)) {
-                               if (!eexp_hw_lasttxstat(dev)) {
-                                       printk("%s: tx interrupt but no status\n", dev->name);
-                               }
-                       }
-
-                       if (SCB_rxdframe(status))
-                               eexp_hw_rx_pio(dev);
-
-                       status = scb_status(dev);
-               } while (status & 0xc000);
-
-               if (SCB_RUdead(status))
-               {
-                       printk(KERN_WARNING "%s: RU stopped: status %04x\n",
-                              dev->name,status);
-#if 0
-                       printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);
-                       outw(lp->cur_rfd, ioaddr+READ_PTR);
-                       printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));
-                       outw(lp->cur_rfd+6, ioaddr+READ_PTR);
-                       printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));
-                       outw(rbd, ioaddr+READ_PTR);
-                       printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));
-                       outw(rbd+8, ioaddr+READ_PTR);
-                       printk("[%04x]\n", inw(ioaddr+DATAPORT));
-#endif
-                       dev->stats.rx_errors++;
-#if 1
-                       eexp_hw_rxinit(dev);
-#else
-                       lp->cur_rfd = lp->first_rfd;
-#endif
-                       scb_wrrfa(dev, lp->rx_buf_start);
-                       scb_command(dev, SCB_RUstart);
-                       outb(0,ioaddr+SIGNAL_CA);
-               }
-       } else {
-               if (status & 0x8000)
-                       ack_cmd = eexp_start_irq(dev, status);
-               else
-                       ack_cmd = SCB_ack(status);
-               scb_command(dev, ack_cmd);
-               outb(0,ioaddr+SIGNAL_CA);
-       }
-
-       eexp_cmd_clear(dev);
-
-       outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-#if NET_DEBUG > 6
-       printk("%s: leaving eexp_irq()\n", dev->name);
-#endif
-       outw(old_read_ptr, ioaddr+READ_PTR);
-       outw(old_write_ptr, ioaddr+WRITE_PTR);
-
-       spin_unlock(&lp->lock);
-       return IRQ_HANDLED;
-}
-
-/*
- * Hardware access functions
- */
-
-/*
- * Set the cable type to use.
- */
-
-static void eexp_hw_set_interface(struct net_device *dev)
-{
-       unsigned char oldval = inb(dev->base_addr + 0x300e);
-       oldval &= ~0x82;
-       switch (dev->if_port) {
-       case TPE:
-               oldval |= 0x2;
-       case BNC:
-               oldval |= 0x80;
-               break;
-       }
-       outb(oldval, dev->base_addr+0x300e);
-       mdelay(20);
-}
-
-/*
- * Check all the receive buffers, and hand any received packets
- * to the upper levels. Basic sanity check on each frame
- * descriptor, though we don't bother trying to fix broken ones.
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short rx_block = lp->rx_ptr;
-       unsigned short boguscount = lp->num_rx_bufs;
-       unsigned short ioaddr = dev->base_addr;
-       unsigned short status;
-
-#if NET_DEBUG > 6
-       printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
-#endif
-
-       do {
-               unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
-
-               outw(rx_block, ioaddr + READ_PTR);
-               status = inw(ioaddr + DATAPORT);
-
-               if (FD_Done(status))
-               {
-                       rfd_cmd = inw(ioaddr + DATAPORT);
-                       rx_next = inw(ioaddr + DATAPORT);
-                       pbuf = inw(ioaddr + DATAPORT);
-
-                       outw(pbuf, ioaddr + READ_PTR);
-                       pkt_len = inw(ioaddr + DATAPORT);
-
-                       if (rfd_cmd!=0x0000)
-                       {
-                               printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",
-                                      dev->name, rfd_cmd);
-                               continue;
-                       }
-                       else if (pbuf!=rx_block+0x16)
-                       {
-                               printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
-                                      dev->name, rx_block+0x16, pbuf);
-                               continue;
-                       }
-                       else if ((pkt_len & 0xc000)!=0xc000)
-                       {
-                               printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
-                                      dev->name, pkt_len & 0xc000);
-                               continue;
-                       }
-                       else if (!FD_OK(status))
-                       {
-                               dev->stats.rx_errors++;
-                               if (FD_CRC(status))
-                                       dev->stats.rx_crc_errors++;
-                               if (FD_Align(status))
-                                       dev->stats.rx_frame_errors++;
-                               if (FD_Resrc(status))
-                                       dev->stats.rx_fifo_errors++;
-                               if (FD_DMA(status))
-                                       dev->stats.rx_over_errors++;
-                               if (FD_Short(status))
-                                       dev->stats.rx_length_errors++;
-                       }
-                       else
-                       {
-                               struct sk_buff *skb;
-                               pkt_len &= 0x3fff;
-                               skb = netdev_alloc_skb(dev, pkt_len + 16);
-                               if (skb == NULL)
-                               {
-                                       printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
-                                       dev->stats.rx_dropped++;
-                                       break;
-                               }
-                               skb_reserve(skb, 2);
-                               outw(pbuf+10, ioaddr+READ_PTR);
-                               insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
-                               skb->protocol = eth_type_trans(skb,dev);
-                               netif_rx(skb);
-                               dev->stats.rx_packets++;
-                               dev->stats.rx_bytes += pkt_len;
-                       }
-                       outw(rx_block, ioaddr+WRITE_PTR);
-                       outw(0, ioaddr+DATAPORT);
-                       outw(0, ioaddr+DATAPORT);
-                       rx_block = rx_next;
-               }
-       } while (FD_Done(status) && boguscount--);
-       lp->rx_ptr = rx_block;
-}
-
-/*
- * Hand a packet to the card for transmission
- * If we get here, we MUST have already checked
- * to make sure there is room in the transmit
- * buffer region.
- */
-
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
-                      unsigned short len)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-
-       if (LOCKUP16 || lp->width) {
-               /* Stop the CU so that there is no chance that it
-                  jumps off to a bogus address while we are writing the
-                  pointer to the next transmit packet in 8-bit mode --
-                  this eliminates the "CU wedged" errors in 8-bit mode.
-                  (Zoltan Szilagyi 10-12-96) */
-               scb_command(dev, SCB_CUsuspend);
-               outw(0xFFFF, ioaddr+SIGNAL_CA);
-       }
-
-       outw(lp->tx_head, ioaddr + WRITE_PTR);
-
-       outw(0x0000, ioaddr + DATAPORT);
-        outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
-
-       outw(0x0000, ioaddr + DATAPORT);
-       outw(0x0000, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-
-       outw(0x8000|len, ioaddr + DATAPORT);
-       outw(-1, ioaddr + DATAPORT);
-       outw(lp->tx_head+0x16, ioaddr + DATAPORT);
-       outw(0, ioaddr + DATAPORT);
-
-       outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
-
-       outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
-       outw(lp->tx_head, ioaddr + DATAPORT);
-
-       dev->trans_start = jiffies;
-       lp->tx_tail = lp->tx_head;
-       if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
-               lp->tx_head = TX_BUF_START;
-       else
-               lp->tx_head += TX_BUF_SIZE;
-       if (lp->tx_head != lp->tx_reap)
-               netif_wake_queue(dev);
-
-       if (LOCKUP16 || lp->width) {
-               /* Restart the CU so that the packet can actually
-                  be transmitted. (Zoltan Szilagyi 10-12-96) */
-               scb_command(dev, SCB_CUresume);
-               outw(0xFFFF, ioaddr+SIGNAL_CA);
-       }
-
-       dev->stats.tx_packets++;
-       lp->last_tx = jiffies;
-}
-
-static const struct net_device_ops eexp_netdev_ops = {
-       .ndo_open               = eexp_open,
-       .ndo_stop               = eexp_close,
-       .ndo_start_xmit         = eexp_xmit,
-       .ndo_set_rx_mode        = eexp_set_multicast,
-       .ndo_tx_timeout         = eexp_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/*
- * Sanity check the suspected EtherExpress card
- * Read hardware address, reset card, size memory and initialize buffer
- * memory pointers. These are held in netdev_priv(), in case someone has more
- * than one card in a machine.
- */
-
-static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
-{
-       unsigned short hw_addr[3];
-       unsigned char buswidth;
-       unsigned int memory_size;
-       int i;
-       unsigned short xsum = 0;
-       struct net_local *lp = netdev_priv(dev);
-
-       printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
-
-       outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
-       outb(0, ioaddr+EEPROM_Ctrl);
-       udelay(500);
-       outb(i586_RST, ioaddr+EEPROM_Ctrl);
-
-       hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
-       hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
-       hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
-
-       /* Standard Address or Compaq LTE Address */
-       if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
-             (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
-       {
-               printk(" rejected: invalid address %04x%04x%04x\n",
-                       hw_addr[2],hw_addr[1],hw_addr[0]);
-               return -ENODEV;
-       }
-
-       /* Calculate the EEPROM checksum.  Carry on anyway if it's bad,
-        * though.
-        */
-       for (i = 0; i < 64; i++)
-               xsum += eexp_hw_readeeprom(ioaddr, i);
-       if (xsum != 0xbaba)
-               printk(" (bad EEPROM xsum 0x%02x)", xsum);
-
-       dev->base_addr = ioaddr;
-       for ( i=0 ; i<6 ; i++ )
-               dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
-
-       {
-               static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
-               unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
-
-               /* Use the IRQ from EEPROM if none was given */
-               if (!dev->irq)
-                       dev->irq = irqmap[setupval>>13];
-
-               if (dev->if_port == 0xff) {
-                       dev->if_port = !(setupval & 0x1000) ? AUI :
-                               eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;
-               }
-
-               buswidth = !((setupval & 0x400) >> 10);
-       }
-
-       memset(lp, 0, sizeof(struct net_local));
-       spin_lock_init(&lp->lock);
-
-       printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
-              eexp_ifmap[dev->if_port], buswidth?8:16);
-
-       if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
-               return -EBUSY;
-
-       eexp_hw_set_interface(dev);
-
-       release_region(dev->base_addr + 0x300e, 1);
-
-       /* Find out how much RAM we have on the card */
-       outw(0, dev->base_addr + WRITE_PTR);
-       for (i = 0; i < 32768; i++)
-               outw(0, dev->base_addr + DATAPORT);
-
-        for (memory_size = 0; memory_size < 64; memory_size++)
-       {
-               outw(memory_size<<10, dev->base_addr + READ_PTR);
-               if (inw(dev->base_addr+DATAPORT))
-                       break;
-               outw(memory_size<<10, dev->base_addr + WRITE_PTR);
-               outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
-               outw(memory_size<<10, dev->base_addr + READ_PTR);
-               if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
-                       break;
-       }
-
-       /* Sort out the number of buffers.  We may have 16, 32, 48 or 64k
-        * of RAM to play with.
-        */
-       lp->num_tx_bufs = 4;
-       lp->rx_buf_end = 0x3ff6;
-       switch (memory_size)
-       {
-       case 64:
-               lp->rx_buf_end += 0x4000;
-       case 48:
-               lp->num_tx_bufs += 4;
-               lp->rx_buf_end += 0x4000;
-       case 32:
-               lp->rx_buf_end += 0x4000;
-       case 16:
-               printk(", %dk RAM)\n", memory_size);
-               break;
-       default:
-               printk(") bad memory size (%dk).\n", memory_size);
-               return -ENODEV;
-               break;
-       }
-
-       lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
-       lp->width = buswidth;
-
-       dev->netdev_ops = &eexp_netdev_ops;
-       dev->watchdog_timeo = 2*HZ;
-
-       return register_netdev(dev);
-}
-
-/*
- * Read a word from the EtherExpress on-board serial EEPROM.
- * The EEPROM contains 64 words of 16 bits.
- */
-static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
-                                                   unsigned char location)
-{
-       unsigned short cmd = 0x180|(location&0x7f);
-       unsigned short rval = 0,wval = EC_CS|i586_RST;
-       int i;
-
-       outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
-       for (i=0x100 ; i ; i>>=1 )
-       {
-               if (cmd&i)
-                       wval |= EC_Wr;
-               else
-                       wval &= ~EC_Wr;
-
-               outb(wval,ioaddr+EEPROM_Ctrl);
-               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-               outb(wval,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-       }
-       wval &= ~EC_Wr;
-       outb(wval,ioaddr+EEPROM_Ctrl);
-       for (i=0x8000 ; i ; i>>=1 )
-       {
-               outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-               if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd)
-                       rval |= i;
-               outb(wval,ioaddr+EEPROM_Ctrl);
-               eeprom_delay();
-       }
-       wval &= ~EC_CS;
-       outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-       eeprom_delay();
-       outb(wval,ioaddr+EEPROM_Ctrl);
-       eeprom_delay();
-       return rval;
-}
-
-/*
- * Reap tx buffers and return last transmit status.
- * if ==0 then either:
- *    a) we're not transmitting anything, so why are we here?
- *    b) we've died.
- * otherwise, Stat_Busy(return) means we've still got some packets
- * to transmit, Stat_Done(return) means our buffers should be empty
- * again
- */
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short tx_block = lp->tx_reap;
-       unsigned short status;
-
-       if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
-               return 0x0000;
-
-       do
-       {
-               outw(tx_block & ~31, dev->base_addr + SM_PTR);
-               status = inw(dev->base_addr + SHADOW(tx_block));
-               if (!Stat_Done(status))
-               {
-                       lp->tx_link = tx_block;
-                       return status;
-               }
-               else
-               {
-                       lp->last_tx_restart = 0;
-                       dev->stats.collisions += Stat_NoColl(status);
-                       if (!Stat_OK(status))
-                       {
-                               char *whatsup = NULL;
-                               dev->stats.tx_errors++;
-                               if (Stat_Abort(status))
-                                       dev->stats.tx_aborted_errors++;
-                               if (Stat_TNoCar(status)) {
-                                       whatsup = "aborted, no carrier";
-                                       dev->stats.tx_carrier_errors++;
-                               }
-                               if (Stat_TNoCTS(status)) {
-                                       whatsup = "aborted, lost CTS";
-                                       dev->stats.tx_carrier_errors++;
-                               }
-                               if (Stat_TNoDMA(status)) {
-                                       whatsup = "FIFO underran";
-                                       dev->stats.tx_fifo_errors++;
-                               }
-                               if (Stat_TXColl(status)) {
-                                       whatsup = "aborted, too many collisions";
-                                       dev->stats.tx_aborted_errors++;
-                               }
-                               if (whatsup)
-                                       printk(KERN_INFO "%s: transmit %s\n",
-                                              dev->name, whatsup);
-                       }
-                       else
-                               dev->stats.tx_packets++;
-               }
-               if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
-                       lp->tx_reap = tx_block = TX_BUF_START;
-               else
-                       lp->tx_reap = tx_block += TX_BUF_SIZE;
-               netif_wake_queue(dev);
-       }
-       while (lp->tx_reap != lp->tx_head);
-
-       lp->tx_link = lp->tx_tail + 0x08;
-
-       return status;
-}
-
-/*
- * This should never happen. It is called when some higher routine detects
- * that the CU has stopped, to try to restart it from the last packet we knew
- * we were working on, or the idle loop if we had finished for the time.
- */
-
-static void eexp_hw_txrestart(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-
-       lp->last_tx_restart = lp->tx_link;
-       scb_wrcbl(dev, lp->tx_link);
-       scb_command(dev, SCB_CUstart);
-       outb(0,ioaddr+SIGNAL_CA);
-
-       {
-               unsigned short boguscount=50,failcount=5;
-               while (!scb_status(dev))
-               {
-                       if (!--boguscount)
-                       {
-                               if (--failcount)
-                               {
-                                       printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
-                                       scb_wrcbl(dev, lp->tx_link);
-                                       scb_command(dev, SCB_CUstart);
-                                       outb(0,ioaddr+SIGNAL_CA);
-                                       boguscount = 100;
-                               }
-                               else
-                               {
-                                       printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
-                                       eexp_hw_init586(dev);
-                                       netif_wake_queue(dev);
-                                       return;
-                               }
-                       }
-               }
-       }
-}
-
-/*
- * Writes down the list of transmit buffers into card memory.  Each
- * entry consists of an 82586 transmit command, followed by a jump
- * pointing to itself.  When we want to transmit a packet, we write
- * the data into the appropriate transmit buffer and then modify the
- * preceding jump to point at the new transmit command.  This means that
- * the 586 command unit is continuously active.
- */
-
-static void eexp_hw_txinit(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short tx_block = TX_BUF_START;
-       unsigned short curtbuf;
-       unsigned short ioaddr = dev->base_addr;
-
-       for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ )
-       {
-               outw(tx_block, ioaddr + WRITE_PTR);
-
-               outw(0x0000, ioaddr + DATAPORT);
-               outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
-               outw(tx_block+0x08, ioaddr + DATAPORT);
-               outw(tx_block+0x0e, ioaddr + DATAPORT);
-
-               outw(0x0000, ioaddr + DATAPORT);
-               outw(0x0000, ioaddr + DATAPORT);
-               outw(tx_block+0x08, ioaddr + DATAPORT);
-
-               outw(0x8000, ioaddr + DATAPORT);
-               outw(-1, ioaddr + DATAPORT);
-               outw(tx_block+0x16, ioaddr + DATAPORT);
-               outw(0x0000, ioaddr + DATAPORT);
-
-               tx_block += TX_BUF_SIZE;
-       }
-       lp->tx_head = TX_BUF_START;
-       lp->tx_reap = TX_BUF_START;
-       lp->tx_tail = tx_block - TX_BUF_SIZE;
-       lp->tx_link = lp->tx_tail + 0x08;
-       lp->rx_buf_start = tx_block;
-
-}
-
-/*
- * Write the circular list of receive buffer descriptors to card memory.
- * The end of the list isn't marked, which means that the 82586 receive
- * unit will loop until buffers become available (this avoids it giving us
- * "out of resources" messages).
- */
-
-static void eexp_hw_rxinit(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short rx_block = lp->rx_buf_start;
-       unsigned short ioaddr = dev->base_addr;
-
-       lp->num_rx_bufs = 0;
-       lp->rx_first = lp->rx_ptr = rx_block;
-       do
-       {
-               lp->num_rx_bufs++;
-
-               outw(rx_block, ioaddr + WRITE_PTR);
-
-               outw(0, ioaddr + DATAPORT);  outw(0, ioaddr+DATAPORT);
-               outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
-               outw(0xffff, ioaddr+DATAPORT);
-
-               outw(0x0000, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-               outw(0xdead, ioaddr+DATAPORT);
-
-               outw(0x0000, ioaddr+DATAPORT);
-               outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT);
-               outw(rx_block + 0x20, ioaddr+DATAPORT);
-               outw(0, ioaddr+DATAPORT);
-               outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT);
-
-               lp->rx_last = rx_block;
-               rx_block += RX_BUF_SIZE;
-       } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
-
-
-       /* Make first Rx frame descriptor point to first Rx buffer
-           descriptor */
-       outw(lp->rx_first + 6, ioaddr+WRITE_PTR);
-       outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-       /* Close Rx frame descriptor ring */
-       outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
-       outw(lp->rx_first, ioaddr+DATAPORT);
-
-       /* Close Rx buffer descriptor ring */
-       outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
-       outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-}
-
-/*
- * Un-reset the 586, and start the configuration sequence. We don't wait for
- * this to finish, but allow the interrupt handler to start the CU and RU for
- * us.  We can't start the receive/transmission system up before we know that
- * the hardware is configured correctly.
- */
-
-static void eexp_hw_init586(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       unsigned short ioaddr = dev->base_addr;
-       int i;
-
-#if NET_DEBUG > 6
-       printk("%s: eexp_hw_init586()\n", dev->name);
-#endif
-
-       lp->started = 0;
-
-       set_loopback(dev);
-
-       outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
-       /* Download the startup code */
-       outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
-       outw(lp->width?0x0001:0x0000, ioaddr + 0x8006);
-       outw(0x0000, ioaddr + 0x8008);
-       outw(0x0000, ioaddr + 0x800a);
-       outw(0x0000, ioaddr + 0x800c);
-       outw(0x0000, ioaddr + 0x800e);
-
-       for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
-               int j;
-               outw(i, ioaddr + SM_PTR);
-               for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
-                       outw(start_code[(i+j)/2],
-                            ioaddr+0x4000+j);
-               for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
-                       outw(start_code[(i+j+16)/2],
-                            ioaddr+0x8000+j);
-       }
-
-       /* Do we want promiscuous mode or multicast? */
-       outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
-       i = inw(ioaddr+SHADOW(CONF_PROMISC));
-       outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
-            ioaddr+SHADOW(CONF_PROMISC));
-       lp->was_promisc = dev->flags & IFF_PROMISC;
-#if 0
-       eexp_setup_filter(dev);
-#endif
-
-       /* Write our hardware address */
-       outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
-       outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
-       outw(((unsigned short *)dev->dev_addr)[1],
-            ioaddr+SHADOW(CONF_HWADDR+2));
-       outw(((unsigned short *)dev->dev_addr)[2],
-            ioaddr+SHADOW(CONF_HWADDR+4));
-
-       eexp_hw_txinit(dev);
-       eexp_hw_rxinit(dev);
-
-       outb(0,ioaddr+EEPROM_Ctrl);
-       mdelay(5);
-
-       scb_command(dev, 0xf000);
-       outb(0,ioaddr+SIGNAL_CA);
-
-       outw(0, ioaddr+SM_PTR);
-
-       {
-               unsigned short rboguscount=50,rfailcount=5;
-               while (inw(ioaddr+0x4000))
-               {
-                       if (!--rboguscount)
-                       {
-                               printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
-                                       dev->name);
-                               scb_command(dev, 0);
-                               outb(0,ioaddr+SIGNAL_CA);
-                               rboguscount = 100;
-                               if (!--rfailcount)
-                               {
-                                       printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
-                                               dev->name);
-                                       return;
-                               }
-                       }
-               }
-       }
-
-        scb_wrcbl(dev, CONF_LINK);
-       scb_command(dev, 0xf000|SCB_CUstart);
-       outb(0,ioaddr+SIGNAL_CA);
-
-       {
-               unsigned short iboguscount=50,ifailcount=5;
-               while (!scb_status(dev))
-               {
-                       if (!--iboguscount)
-                       {
-                               if (--ifailcount)
-                               {
-                                       printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
-                                               dev->name, scb_status(dev), scb_rdcmd(dev));
-                                       scb_wrcbl(dev, CONF_LINK);
-                                       scb_command(dev, 0xf000|SCB_CUstart);
-                                       outb(0,ioaddr+SIGNAL_CA);
-                                       iboguscount = 100;
-                               }
-                               else
-                               {
-                                       printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
-                                       return;
-                               }
-                       }
-               }
-       }
-
-       clear_loopback(dev);
-       outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
-       lp->init_time = jiffies;
-#if NET_DEBUG > 6
-        printk("%s: leaving eexp_hw_init586()\n", dev->name);
-#endif
-}
-
-static void eexp_setup_filter(struct net_device *dev)
-{
-       struct netdev_hw_addr *ha;
-       unsigned short ioaddr = dev->base_addr;
-       int count = netdev_mc_count(dev);
-       int i;
-       if (count > 8) {
-               printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
-                      dev->name, count);
-               count = 8;
-       }
-
-       outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
-       outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
-       i = 0;
-       netdev_for_each_mc_addr(ha, dev) {
-               unsigned short *data = (unsigned short *) ha->addr;
-
-               if (i == count)
-                       break;
-               outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
-               outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
-               outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
-               outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
-               outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
-               outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
-               i++;
-       }
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-static void
-eexp_set_multicast(struct net_device *dev)
-{
-        unsigned short ioaddr = dev->base_addr;
-        struct net_local *lp = netdev_priv(dev);
-        int kick = 0, i;
-        if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
-                outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
-                i = inw(ioaddr+SHADOW(CONF_PROMISC));
-                outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
-                     ioaddr+SHADOW(CONF_PROMISC));
-                lp->was_promisc = dev->flags & IFF_PROMISC;
-                kick = 1;
-        }
-        if (!(dev->flags & IFF_PROMISC)) {
-                eexp_setup_filter(dev);
-                if (lp->old_mc_count != netdev_mc_count(dev)) {
-                        kick = 1;
-                        lp->old_mc_count = netdev_mc_count(dev);
-                }
-        }
-        if (kick) {
-                unsigned long oj;
-                scb_command(dev, SCB_CUsuspend);
-                outb(0, ioaddr+SIGNAL_CA);
-                outb(0, ioaddr+SIGNAL_CA);
-#if 0
-                printk("%s: waiting for CU to go suspended\n", dev->name);
-#endif
-                oj = jiffies;
-                while ((SCB_CUstat(scb_status(dev)) == 2) &&
-                       (time_before(jiffies, oj + 2000)));
-               if (SCB_CUstat(scb_status(dev)) == 2)
-                       printk("%s: warning, CU didn't stop\n", dev->name);
-                lp->started &= ~(STARTED_CU);
-                scb_wrcbl(dev, CONF_LINK);
-                scb_command(dev, SCB_CUstart);
-                outb(0, ioaddr+SIGNAL_CA);
-        }
-}
-
-
-/*
- * MODULE stuff
- */
-
-#ifdef MODULE
-
-#define EEXP_MAX_CARDS     4    /* max number of cards to support */
-
-static struct net_device *dev_eexp[EEXP_MAX_CARDS];
-static int irq[EEXP_MAX_CARDS];
-static int io[EEXP_MAX_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
-MODULE_LICENSE("GPL");
-
-
-/* Ideally the user would give us io=, irq= for every card.  If any parameters
- * are specified, we verify and then use them.  If no parameters are given, we
- * autoprobe for one card only.
- */
-int __init init_module(void)
-{
-       struct net_device *dev;
-       int this_dev, found = 0;
-
-       for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
-               dev = alloc_etherdev(sizeof(struct net_local));
-               dev->irq = irq[this_dev];
-               dev->base_addr = io[this_dev];
-               if (io[this_dev] == 0) {
-                       if (this_dev)
-                               break;
-                       printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
-               }
-               if (do_express_probe(dev) == 0) {
-                       dev_eexp[this_dev] = dev;
-                       found++;
-                       continue;
-               }
-               printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
-               free_netdev(dev);
-               break;
-       }
-       if (found)
-               return 0;
-       return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
-       int this_dev;
-
-       for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
-               struct net_device *dev = dev_eexp[this_dev];
-               if (dev) {
-                       unregister_netdev(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif
-
-/*
- * Local Variables:
- *  c-file-style: "linux"
- *  tab-width: 8
- * End:
- */
diff --git a/drivers/net/ethernet/i825xx/eexpress.h b/drivers/net/ethernet/i825xx/eexpress.h
deleted file mode 100644 (file)
index dc9c6ea..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * eexpress.h: Intel EtherExpress16 defines
- */
-
-/*
- * EtherExpress card register addresses
- * as offsets from the base IO region (dev->base_addr)
- */
-
-#define DATAPORT      0x0000
-#define WRITE_PTR     0x0002
-#define READ_PTR      0x0004
-#define SIGNAL_CA     0x0006
-#define SET_IRQ       0x0007
-#define SM_PTR        0x0008
-#define        MEM_Dec       0x000a
-#define MEM_Ctrl      0x000b
-#define MEM_Page_Ctrl 0x000c
-#define Config        0x000d
-#define EEPROM_Ctrl   0x000e
-#define ID_PORT       0x000f
-#define        MEM_ECtrl     0x000f
-
-/*
- * card register defines
- */
-
-/* SET_IRQ */
-#define SIRQ_en       0x08
-#define SIRQ_dis      0x00
-
-/* EEPROM_Ctrl */
-#define EC_Clk        0x01
-#define EC_CS         0x02
-#define EC_Wr         0x04
-#define EC_Rd         0x08
-#define ASIC_RST      0x40
-#define i586_RST      0x80
-
-#define eeprom_delay() { udelay(40); }
-
-/*
- * i82586 Memory Configuration
- */
-
-/* (System Configuration Pointer) System start up block, read after 586_RST */
-#define SCP_START 0xfff6
-
-/* Intermediate System Configuration Pointer */
-#define ISCP_START 0x0000
-
-/* System Command Block */
-#define SCB_START 0x0008
-
-/* Start of buffer region.  Everything before this is used for control
- * structures and the CU configuration program.  The memory layout is
- * determined in eexp_hw_probe(), once we know how much memory is
- * available on the card.
- */
-
-#define TX_BUF_START 0x0100
-
-#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
-#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
-
-/*
- * SCB defines
- */
-
-/* these functions take the SCB status word and test the relevant status bit */
-#define SCB_complete(s) (((s) & 0x8000) != 0)
-#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
-#define SCB_CUdead(s)   (((s) & 0x2000) != 0)
-#define SCB_RUdead(s)   (((s) & 0x1000) != 0)
-#define SCB_ack(s)      ((s) & 0xf000)
-
-/* Command unit status: 0=idle, 1=suspended, 2=active */
-#define SCB_CUstat(s)   (((s)&0x0300)>>8)
-
-/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
-#define SCB_RUstat(s)   (((s)&0x0070)>>4)
-
-/* SCB commands */
-#define SCB_CUnop       0x0000
-#define SCB_CUstart     0x0100
-#define SCB_CUresume    0x0200
-#define SCB_CUsuspend   0x0300
-#define SCB_CUabort     0x0400
-#define SCB_resetchip   0x0080
-
-#define SCB_RUnop       0x0000
-#define SCB_RUstart     0x0010
-#define SCB_RUresume    0x0020
-#define SCB_RUsuspend   0x0030
-#define SCB_RUabort     0x0040
-
-/*
- * Command block defines
- */
-
-#define Stat_Done(s)    (((s) & 0x8000) != 0)
-#define Stat_Busy(s)    (((s) & 0x4000) != 0)
-#define Stat_OK(s)      (((s) & 0x2000) != 0)
-#define Stat_Abort(s)   (((s) & 0x1000) != 0)
-#define Stat_STFail     (((s) & 0x0800) != 0)
-#define Stat_TNoCar(s)  (((s) & 0x0400) != 0)
-#define Stat_TNoCTS(s)  (((s) & 0x0200) != 0)
-#define Stat_TNoDMA(s)  (((s) & 0x0100) != 0)
-#define Stat_TDefer(s)  (((s) & 0x0080) != 0)
-#define Stat_TColl(s)   (((s) & 0x0040) != 0)
-#define Stat_TXColl(s)  (((s) & 0x0020) != 0)
-#define Stat_NoColl(s)  ((s) & 0x000f)
-
-/* Cmd_END will end AFTER the command if this is the first
- * command block after an SCB_CUstart, but BEFORE the command
- * for all subsequent commands. Best strategy is to place
- * Cmd_INT on the last command in the sequence, followed by a
- * dummy Cmd_Nop with Cmd_END after this.
- */
-
-#define Cmd_END     0x8000
-#define Cmd_SUS     0x4000
-#define Cmd_INT     0x2000
-
-#define Cmd_Nop     0x0000
-#define Cmd_SetAddr 0x0001
-#define Cmd_Config  0x0002
-#define Cmd_MCast   0x0003
-#define Cmd_Xmit    0x0004
-#define Cmd_TDR     0x0005
-#define Cmd_Dump    0x0006
-#define Cmd_Diag    0x0007
-
-
-/*
- * Frame Descriptor (Receive block) defines
- */
-
-#define FD_Done(s)  (((s) & 0x8000) != 0)
-#define FD_Busy(s)  (((s) & 0x4000) != 0)
-#define FD_OK(s)    (((s) & 0x2000) != 0)
-
-#define FD_CRC(s)   (((s) & 0x0800) != 0)
-#define FD_Align(s) (((s) & 0x0400) != 0)
-#define FD_Resrc(s) (((s) & 0x0200) != 0)
-#define FD_DMA(s)   (((s) & 0x0100) != 0)
-#define FD_Short(s) (((s) & 0x0080) != 0)
-#define FD_NoEOF(s) (((s) & 0x0040) != 0)
-
-struct rfd_header {
-       volatile unsigned long flags;
-       volatile unsigned short link;
-       volatile unsigned short rbd_offset;
-       volatile unsigned short dstaddr1;
-       volatile unsigned short dstaddr2;
-       volatile unsigned short dstaddr3;
-       volatile unsigned short srcaddr1;
-       volatile unsigned short srcaddr2;
-       volatile unsigned short srcaddr3;
-       volatile unsigned short length;
-
-       /* This is actually a Receive Buffer Descriptor.  The way we
-        * arrange memory means that an RBD always follows the RFD that
-        * points to it, so they might as well be in the same structure.
-        */
-       volatile unsigned short actual_count;
-       volatile unsigned short next_rbd;
-       volatile unsigned short buf_addr1;
-       volatile unsigned short buf_addr2;
-       volatile unsigned short size;
-};
-
-/* Returned data from the Time Domain Reflectometer */
-
-#define TDR_LINKOK       (1<<15)
-#define TDR_XCVRPROBLEM  (1<<14)
-#define TDR_OPEN         (1<<13)
-#define TDR_SHORT        (1<<12)
-#define TDR_TIME         0x7ff
diff --git a/drivers/net/ethernet/i825xx/lp486e.c b/drivers/net/ethernet/i825xx/lp486e.c
deleted file mode 100644 (file)
index 3735bfa..0000000
+++ /dev/null
@@ -1,1337 +0,0 @@
-/* Intel Professional Workstation/panther ethernet driver */
-/* lp486e.c: A panther 82596 ethernet driver for linux. */
-/*
-    History and copyrights:
-
-    Driver skeleton
-        Written 1993 by Donald Becker.
-        Copyright 1993 United States Government as represented by the Director,
-        National Security Agency.  This software may only be used and
-       distributed according to the terms of the GNU General Public License
-       as modified by SRC, incorporated herein by reference.
-
-        The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-    Apricot
-        Written 1994 by Mark Evans.
-        This driver is for the Apricot 82596 bus-master interface
-
-        Modularised 12/94 Mark Evans
-
-    Professional Workstation
-       Derived from apricot.c by Ard van Breemen
-       <ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
-
-       Credits:
-       Thanks to Murphy Software BV for letting me write this in their time.
-       Well, actually, I get paid doing this...
-       (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
-       more information on the Professional Workstation)
-
-    Present version
-       aeb@cwi.nl
-*/
-/*
-    There are currently two motherboards that I know of in the
-    professional workstation. The only one that I know is the
-    intel panther motherboard. -- ard
-*/
-/*
-The pws is equipped with an intel 82596. This is a very intelligent controller
-which runs its own micro-code. Communication with the hostprocessor is done
-through linked lists of commands and buffers in the hostprocessors memory.
-A complete description of the 82596 is available from intel. Search for
-a file called "29021806.pdf". It is a complete description of the chip itself.
-To use it for the pws some additions are needed regarding generation of
-the PORT and CA signal, and the interrupt glue needed for a pc.
-I/O map:
-PORT  SIZE ACTION MEANING
-0xCB0    2 WRITE  Lower 16 bits for PORT command
-0xCB2    2 WRITE  Upper 16 bits for PORT command, and issue of PORT command
-0xCB4    1 WRITE  Generation of CA signal
-0xCB8    1 WRITE  Clear interrupt glue
-All other communication is through memory!
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "lp486e"
-
-/* debug print flags */
-#define LOG_SRCDST    0x80000000
-#define LOG_STATINT   0x40000000
-#define LOG_STARTINT  0x20000000
-
-#define i596_debug debug
-
-static int i596_debug = 0;
-
-static const char * const medianame[] = {
-       "10baseT", "AUI",
-       "10baseT-FD", "AUI-FD",
-};
-
-#define LP486E_TOTAL_SIZE 16
-
-#define I596_NULL (0xffffffff)
-
-#define CMD_EOL                0x8000  /* The last command of the list, stop. */
-#define CMD_SUSP       0x4000  /* Suspend after doing cmd. */
-#define CMD_INTR       0x2000  /* Interrupt after doing cmd. */
-
-#define CMD_FLEX       0x0008  /* Enable flexible memory model */
-
-enum commands {
-       CmdNOP = 0,
-       CmdIASetup = 1,
-       CmdConfigure = 2,
-       CmdMulticastList = 3,
-       CmdTx = 4,
-       CmdTDR = 5,
-       CmdDump = 6,
-       CmdDiagnose = 7
-};
-
-#if 0
-static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
-                                    "Tx", "TDR", "Dump", "Diagnose" };
-#endif
-
-/* Status word bits */
-#define        STAT_CX         0x8000  /* The CU finished executing a command
-                                  with the Interrupt bit set */
-#define        STAT_FR         0x4000  /* The RU finished receiving a frame */
-#define        STAT_CNA        0x2000  /* The CU left the active state */
-#define        STAT_RNR        0x1000  /* The RU left the active state */
-#define STAT_ACK       (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
-#define        STAT_CUS        0x0700  /* Status of CU: 0: idle, 1: suspended,
-                                  2: active, 3-7: unused */
-#define STAT_RUS       0x00f0  /* Status of RU: 0: idle, 1: suspended,
-                                  2: no resources, 4: ready,
-                                  10: no resources due to no more RBDs,
-                                  12: no more RBDs, other: unused */
-#define        STAT_T          0x0008  /* Bus throttle timers loaded */
-#define        STAT_ZERO       0x0807  /* Always zero */
-
-#if 0
-static char *CUstates[8] = {
-       "idle", "suspended", "active", 0, 0, 0, 0, 0
-};
-static char *RUstates[16] = {
-       "idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
-       0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
-};
-
-static void
-i596_out_status(int status) {
-       int bad = 0;
-       char *s;
-
-       printk("status %4.4x:", status);
-       if (status == 0xffff)
-               printk(" strange..\n");
-       else {
-               if (status & STAT_CX)
-                       printk("  CU done");
-               if (status & STAT_CNA)
-                       printk("  CU stopped");
-               if (status & STAT_FR)
-                       printk("  got a frame");
-               if (status & STAT_RNR)
-                       printk("  RU stopped");
-               if (status & STAT_T)
-                       printk("  throttled");
-               if (status & STAT_ZERO)
-                       bad = 1;
-               s = CUstates[(status & STAT_CUS) >> 8];
-               if (!s)
-                       bad = 1;
-               else
-                       printk("  CU(%s)", s);
-               s = RUstates[(status & STAT_RUS) >> 4];
-               if (!s)
-                       bad = 1;
-               else
-                       printk("  RU(%s)", s);
-               if (bad)
-                       printk("  bad status");
-               printk("\n");
-       }
-}
-#endif
-
-/* Command word bits */
-#define ACK_CX         0x8000
-#define ACK_FR         0x4000
-#define ACK_CNA                0x2000
-#define ACK_RNR                0x1000
-
-#define CUC_START      0x0100
-#define CUC_RESUME     0x0200
-#define CUC_SUSPEND    0x0300
-#define CUC_ABORT      0x0400
-
-#define RX_START       0x0010
-#define RX_RESUME      0x0020
-#define RX_SUSPEND     0x0030
-#define RX_ABORT       0x0040
-
-typedef u32 phys_addr;
-
-static inline phys_addr
-va_to_pa(void *x) {
-       return x ? virt_to_bus(x) : I596_NULL;
-}
-
-static inline void *
-pa_to_va(phys_addr x) {
-       return (x == I596_NULL) ? NULL : bus_to_virt(x);
-}
-
-/* status bits for cmd */
-#define CMD_STAT_C     0x8000  /* CU command complete */
-#define CMD_STAT_B     0x4000  /* CU command in progress */
-#define CMD_STAT_OK    0x2000  /* CU command completed without errors */
-#define CMD_STAT_A     0x1000  /* CU command abnormally terminated */
-
-struct i596_cmd {              /* 8 bytes */
-       unsigned short status;
-       unsigned short command;
-       phys_addr pa_next;      /* va_to_pa(struct i596_cmd *next) */
-};
-
-#define EOF            0x8000
-#define SIZE_MASK      0x3fff
-
-struct i596_tbd {
-       unsigned short size;
-       unsigned short pad;
-       phys_addr pa_next;      /* va_to_pa(struct i596_tbd *next) */
-       phys_addr pa_data;      /* va_to_pa(char *data) */
-       struct sk_buff *skb;
-};
-
-struct tx_cmd {
-       struct i596_cmd cmd;
-       phys_addr pa_tbd;       /* va_to_pa(struct i596_tbd *tbd) */
-       unsigned short size;
-       unsigned short pad;
-};
-
-/* status bits for rfd */
-#define RFD_STAT_C     0x8000  /* Frame reception complete */
-#define RFD_STAT_B     0x4000  /* Frame reception in progress */
-#define RFD_STAT_OK    0x2000  /* Frame received without errors */
-#define RFD_STATUS     0x1fff
-#define RFD_LENGTH_ERR 0x1000
-#define RFD_CRC_ERR    0x0800
-#define RFD_ALIGN_ERR  0x0400
-#define RFD_NOBUFS_ERR 0x0200
-#define RFD_DMA_ERR    0x0100  /* DMA overrun failure to acquire system bus */
-#define RFD_SHORT_FRAME_ERR    0x0080
-#define RFD_NOEOP_ERR  0x0040
-#define RFD_TRUNC_ERR  0x0020
-#define RFD_MULTICAST  0x0002  /* 0: destination had our address
-                                  1: destination was broadcast/multicast */
-#define RFD_COLLISION  0x0001
-
-/* receive frame descriptor */
-struct i596_rfd {
-       unsigned short stat;
-       unsigned short cmd;
-       phys_addr pa_next;      /* va_to_pa(struct i596_rfd *next) */
-       phys_addr pa_rbd;       /* va_to_pa(struct i596_rbd *rbd) */
-       unsigned short count;
-       unsigned short size;
-       char data[1532];
-};
-
-#define RBD_EL         0x8000
-#define RBD_P          0x4000
-#define RBD_SIZEMASK   0x3fff
-#define RBD_EOF                0x8000
-#define RBD_F          0x4000
-
-/* receive buffer descriptor */
-struct i596_rbd {
-       unsigned short size;
-       unsigned short pad;
-       phys_addr pa_next;      /* va_to_pa(struct i596_tbd *next) */
-       phys_addr pa_data;      /* va_to_pa(char *data) */
-       phys_addr pa_prev;      /* va_to_pa(struct i596_tbd *prev) */
-
-       /* Driver private part */
-       struct sk_buff *skb;
-};
-
-#define RX_RING_SIZE 64
-#define RX_SKBSIZE (ETH_FRAME_LEN+10)
-#define RX_RBD_SIZE 32
-
-/* System Control Block - 40 bytes */
-struct i596_scb {
-       u16 status;             /* 0 */
-       u16 command;            /* 2 */
-       phys_addr pa_cmd;       /* 4 - va_to_pa(struct i596_cmd *cmd) */
-       phys_addr pa_rfd;       /* 8 - va_to_pa(struct i596_rfd *rfd) */
-       u32 crc_err;            /* 12 */
-       u32 align_err;          /* 16 */
-       u32 resource_err;       /* 20 */
-       u32 over_err;           /* 24 */
-       u32 rcvdt_err;          /* 28 */
-       u32 short_err;          /* 32 */
-       u16 t_on;               /* 36 */
-       u16 t_off;              /* 38 */
-};
-
-/* Intermediate System Configuration Pointer - 8 bytes */
-struct i596_iscp {
-       u32 busy;               /* 0 */
-       phys_addr pa_scb;       /* 4 - va_to_pa(struct i596_scb *scb) */
-};
-
-/* System Configuration Pointer - 12 bytes */
-struct i596_scp {
-       u32 sysbus;             /* 0 */
-       u32 pad;                /* 4 */
-       phys_addr pa_iscp;      /* 8 - va_to_pa(struct i596_iscp *iscp) */
-};
-
-/* Selftest and dump results - needs 16-byte alignment */
-/*
- * The size of the dump area is 304 bytes. When the dump is executed
- * by the Port command an extra word will be appended to the dump area.
- * The extra word is a copy of the Dump status word (containing the
- * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
- */
-struct i596_dump {
-       u16 dump[153];          /* (304 = 130h) + 2 bytes */
-};
-
-struct i596_private {          /* aligned to a 16-byte boundary */
-       struct i596_scp scp;    /* 0 - needs 16-byte alignment */
-       struct i596_iscp iscp;  /* 12 */
-       struct i596_scb scb;    /* 20 */
-       u32 dummy;              /* 60 */
-       struct i596_dump dump;  /* 64 - needs 16-byte alignment */
-
-       struct i596_cmd set_add;
-       char eth_addr[8];       /* directly follows set_add */
-
-       struct i596_cmd set_conf;
-       char i596_config[16];   /* directly follows set_conf */
-
-       struct i596_cmd tdr;
-       unsigned long tdr_stat; /* directly follows tdr */
-
-       int last_restart;
-       struct i596_rbd *rbd_list;
-       struct i596_rbd *rbd_tail;
-       struct i596_rfd *rx_tail;
-       struct i596_cmd *cmd_tail;
-       struct i596_cmd *cmd_head;
-       int cmd_backlog;
-       unsigned long last_cmd;
-       spinlock_t cmd_lock;
-};
-
-static char init_setup[14] = {
-       0x8E,   /* length 14 bytes, prefetch on */
-       0xC8,   /* default: fifo to 8, monitor off */
-       0x40,   /* default: don't save bad frames (apricot.c had 0x80) */
-       0x2E,   /* (default is 0x26)
-                  No source address insertion, 8 byte preamble */
-       0x00,   /* default priority and backoff */
-       0x60,   /* default interframe spacing */
-       0x00,   /* default slot time LSB */
-       0xf2,   /* default slot time and nr of retries */
-       0x00,   /* default various bits
-                  (0: promiscuous mode, 1: broadcast disable,
-                   2: encoding mode, 3: transmit on no CRS,
-                   4: no CRC insertion, 5: CRC type,
-                   6: bit stuffing, 7: padding) */
-       0x00,   /* default carrier sense and collision detect */
-       0x40,   /* default minimum frame length */
-       0xff,   /* (default is 0xff, and that is what apricot.c has;
-                  elp486.c has 0xfb: Enable crc append in memory.) */
-       0x00,   /* default: not full duplex */
-       0x7f    /* (default is 0x3f) multi IA */
-};
-
-static int i596_open(struct net_device *dev);
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void print_eth(char *);
-static void set_multicast_list(struct net_device *dev);
-static void i596_tx_timeout(struct net_device *dev);
-
-static int
-i596_timeout(struct net_device *dev, char *msg, int ct) {
-       struct i596_private *lp;
-       int boguscnt = ct;
-
-       lp = netdev_priv(dev);
-       while (lp->scb.command) {
-               if (--boguscnt == 0) {
-                       printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
-                              dev->name, msg,
-                              lp->scb.status, lp->scb.command);
-                       return 1;
-               }
-               udelay(5);
-               barrier();
-       }
-       return 0;
-}
-
-static inline int
-init_rx_bufs(struct net_device *dev, int num) {
-       struct i596_private *lp;
-       struct i596_rfd *rfd;
-       int i;
-       // struct i596_rbd *rbd;
-
-       lp = netdev_priv(dev);
-       lp->scb.pa_rfd = I596_NULL;
-
-       for (i = 0; i < num; i++) {
-               rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
-               if (rfd == NULL)
-                       break;
-
-               rfd->stat = 0;
-               rfd->pa_rbd = I596_NULL;
-               rfd->count = 0;
-               rfd->size = 1532;
-               if (i == 0) {
-                       rfd->cmd = CMD_EOL;
-                       lp->rx_tail = rfd;
-               } else {
-                       rfd->cmd = 0;
-               }
-               rfd->pa_next = lp->scb.pa_rfd;
-               lp->scb.pa_rfd = va_to_pa(rfd);
-               lp->rx_tail->pa_next = lp->scb.pa_rfd;
-       }
-
-#if 0
-       for (i = 0; i<RX_RBD_SIZE; i++) {
-               rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
-               if (rbd) {
-                       rbd->pad = 0;
-                       rbd->count = 0;
-                       rbd->skb = dev_alloc_skb(RX_SKBSIZE);
-                       if (!rbd->skb) {
-                               printk("dev_alloc_skb failed");
-                       }
-                       rbd->next = rfd->rbd;
-                       if (i) {
-                               rfd->rbd->prev = rbd;
-                               rbd->size = RX_SKBSIZE;
-                       } else {
-                               rbd->size = (RX_SKBSIZE | RBD_EL);
-                               lp->rbd_tail = rbd;
-                       }
-
-                       rfd->rbd = rbd;
-               }
-       }
-       lp->rbd_tail->next = rfd->rbd;
-#endif
-       return i;
-}
-
-static inline void
-remove_rx_bufs(struct net_device *dev) {
-       struct i596_private *lp;
-       struct i596_rfd *rfd;
-
-       lp = netdev_priv(dev);
-       lp->rx_tail->pa_next = I596_NULL;
-
-       do {
-               rfd = pa_to_va(lp->scb.pa_rfd);
-               lp->scb.pa_rfd = rfd->pa_next;
-               kfree(rfd);
-       } while (rfd != lp->rx_tail);
-
-       lp->rx_tail = NULL;
-
-#if 0
-       for (lp->rbd_list) {
-       }
-#endif
-}
-
-#define PORT_RESET              0x00    /* reset 82596 */
-#define PORT_SELFTEST           0x01    /* selftest */
-#define PORT_ALTSCP             0x02    /* alternate SCB address */
-#define PORT_DUMP               0x03    /* dump */
-
-#define IOADDR 0xcb0           /* real constant */
-#define IRQ    10              /* default IRQ - can be changed by ECU */
-
-/* The 82596 requires two 16-bit write cycles for a port command */
-static inline void
-PORT(phys_addr a, unsigned int cmd) {
-       if (a & 0xf)
-               printk("lp486e.c: PORT: address not aligned\n");
-       outw(((a & 0xffff) | cmd), IOADDR);
-       outw(((a>>16) & 0xffff), IOADDR+2);
-}
-
-static inline void
-CA(void) {
-       outb(0, IOADDR+4);
-       udelay(8);
-}
-
-static inline void
-CLEAR_INT(void) {
-       outb(0, IOADDR+8);
-}
-
-#if 0
-/* selftest or dump */
-static void
-i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
-       struct i596_private *lp = netdev_priv(dev);
-       u16 *outp;
-       int i, m;
-
-       memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
-       outp = &(lp->dump.dump[0]);
-
-       PORT(va_to_pa(outp), portcmd);
-       mdelay(30);             /* random, unmotivated */
-
-       printk("lp486e i82596 %s result:\n", cmdname);
-       for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
-               ;
-       for (i = 0; i < m; i++) {
-               printk(" %04x", lp->dump.dump[i]);
-               if (i%8 == 7)
-                       printk("\n");
-       }
-       printk("\n");
-}
-#endif
-
-static int
-i596_scp_setup(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       int boguscnt;
-
-       /* Setup SCP, ISCP, SCB */
-       /*
-        * sysbus bits:
-        *  only a single byte is significant - here 0x44
-        *  0x80: big endian mode (details depend on stepping)
-        *  0x40: 1
-        *  0x20: interrupt pin is active low
-        *  0x10: lock function disabled
-        *  0x08: external triggering of bus throttle timers
-        *  0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
-        *  0x01: unused
-        */
-       lp->scp.sysbus = 0x00440000;            /* linear mode */
-       lp->scp.pad = 0;                        /* must be zero */
-       lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
-
-       /*
-        * The CPU sets the ISCP to 1 before it gives the first CA()
-        */
-       lp->iscp.busy = 0x0001;
-       lp->iscp.pa_scb = va_to_pa(&(lp->scb));
-
-       lp->scb.command = 0;
-       lp->scb.status = 0;
-       lp->scb.pa_cmd = I596_NULL;
-       /* lp->scb.pa_rfd has been initialised already */
-
-       lp->last_cmd = jiffies;
-       lp->cmd_backlog = 0;
-       lp->cmd_head = NULL;
-
-       /*
-        * Reset the 82596.
-        * We need to wait 10 systemclock cycles, and
-        * 5 serial clock cycles.
-        */
-       PORT(0, PORT_RESET);    /* address part ignored */
-       udelay(100);
-
-       /*
-        * Before the CA signal is asserted, the default SCP address
-        * (0x00fffff4) can be changed to a 16-byte aligned value
-        */
-       PORT(va_to_pa(&lp->scp), PORT_ALTSCP);  /* change the scp address */
-
-       /*
-        * The initialization procedure begins when a
-        * Channel Attention signal is asserted after a reset.
-        */
-
-       CA();
-
-       /*
-        * The ISCP busy is cleared by the 82596 after the SCB address is read.
-        */
-       boguscnt = 100;
-       while (lp->iscp.busy) {
-               if (--boguscnt == 0) {
-                       /* No i82596 present? */
-                       printk("%s: i82596 initialization timed out\n",
-                              dev->name);
-                       return 1;
-               }
-               udelay(5);
-               barrier();
-       }
-       /* I find here boguscnt==100, so no delay was required. */
-
-       return 0;
-}
-
-static int
-init_i596(struct net_device *dev) {
-       struct i596_private *lp;
-
-       if (i596_scp_setup(dev))
-               return 1;
-
-       lp = netdev_priv(dev);
-       lp->scb.command = 0;
-
-       memcpy ((void *)lp->i596_config, init_setup, 14);
-       lp->set_conf.command = CmdConfigure;
-       i596_add_cmd(dev, (void *)&lp->set_conf);
-
-       memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
-       lp->set_add.command = CmdIASetup;
-       i596_add_cmd(dev, &lp->set_add);
-
-       lp->tdr.command = CmdTDR;
-       i596_add_cmd(dev, &lp->tdr);
-
-       if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
-               return 1;
-
-       lp->scb.command = RX_START;
-       CA();
-
-       barrier();
-
-       if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
-               return 1;
-
-       return 0;
-}
-
-/* Receive a single frame */
-static inline int
-i596_rx_one(struct net_device *dev, struct i596_private *lp,
-           struct i596_rfd *rfd, int *frames) {
-
-       if (rfd->stat & RFD_STAT_OK) {
-               /* a good frame */
-               int pkt_len = (rfd->count & 0x3fff);
-               struct sk_buff *skb = netdev_alloc_skb(dev, pkt_len);
-
-               (*frames)++;
-
-               if (rfd->cmd & CMD_EOL)
-                       printk("Received on EOL\n");
-
-               if (skb == NULL) {
-                       printk ("%s: i596_rx Memory squeeze, "
-                               "dropping packet.\n", dev->name);
-                       dev->stats.rx_dropped++;
-                       return 1;
-               }
-
-               memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
-
-               skb->protocol = eth_type_trans(skb,dev);
-               netif_rx(skb);
-               dev->stats.rx_packets++;
-       } else {
-#if 0
-               printk("Frame reception error status %04x\n",
-                      rfd->stat);
-#endif
-               dev->stats.rx_errors++;
-               if (rfd->stat & RFD_COLLISION)
-                       dev->stats.collisions++;
-               if (rfd->stat & RFD_SHORT_FRAME_ERR)
-                       dev->stats.rx_length_errors++;
-               if (rfd->stat & RFD_DMA_ERR)
-                       dev->stats.rx_over_errors++;
-               if (rfd->stat & RFD_NOBUFS_ERR)
-                       dev->stats.rx_fifo_errors++;
-               if (rfd->stat & RFD_ALIGN_ERR)
-                       dev->stats.rx_frame_errors++;
-               if (rfd->stat & RFD_CRC_ERR)
-                       dev->stats.rx_crc_errors++;
-               if (rfd->stat & RFD_LENGTH_ERR)
-                       dev->stats.rx_length_errors++;
-       }
-       rfd->stat = rfd->count = 0;
-       return 0;
-}
-
-static int
-i596_rx(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_rfd *rfd;
-       int frames = 0;
-
-       while (1) {
-               rfd = pa_to_va(lp->scb.pa_rfd);
-               if (!rfd) {
-                       printk(KERN_ERR "i596_rx: NULL rfd?\n");
-                       return 0;
-               }
-#if 1
-               if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
-                       printk("SF:%p-%04x\n", rfd, rfd->stat);
-#endif
-               if (!(rfd->stat & RFD_STAT_C))
-                       break;          /* next one not ready */
-               if (i596_rx_one(dev, lp, rfd, &frames))
-                       break;          /* out of memory */
-               rfd->cmd = CMD_EOL;
-               lp->rx_tail->cmd = 0;
-               lp->rx_tail = rfd;
-               lp->scb.pa_rfd = rfd->pa_next;
-               barrier();
-       }
-
-       return frames;
-}
-
-static void
-i596_cleanup_cmd(struct net_device *dev) {
-       struct i596_private *lp;
-       struct i596_cmd *cmd;
-
-       lp = netdev_priv(dev);
-       while (lp->cmd_head) {
-               cmd = lp->cmd_head;
-
-               lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
-               lp->cmd_backlog--;
-
-               switch ((cmd->command) & 0x7) {
-                       case CmdTx: {
-                               struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
-                               struct i596_tbd * tx_cmd_tbd;
-                               tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
-                               dev_kfree_skb_any(tx_cmd_tbd->skb);
-
-                               dev->stats.tx_errors++;
-                               dev->stats.tx_aborted_errors++;
-
-                               cmd->pa_next = I596_NULL;
-                               kfree((unsigned char *)tx_cmd);
-                               netif_wake_queue(dev);
-                               break;
-                       }
-                       case CmdMulticastList: {
-                               // unsigned short count = *((unsigned short *) (ptr + 1));
-
-                               cmd->pa_next = I596_NULL;
-                               kfree((unsigned char *)cmd);
-                               break;
-                       }
-                       default: {
-                               cmd->pa_next = I596_NULL;
-                               break;
-                       }
-               }
-               barrier();
-       }
-
-       if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
-               ;
-
-       lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-}
-
-static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) {
-
-       if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
-               ;
-
-       netif_stop_queue(dev);
-
-       lp->scb.command = CUC_ABORT | RX_ABORT;
-       CA();
-       barrier();
-
-       /* wait for shutdown */
-       if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
-               ;
-
-       i596_cleanup_cmd(dev);
-       i596_rx(dev);
-
-       netif_start_queue(dev);
-       /*dev_kfree_skb(skb, FREE_WRITE);*/
-       init_i596(dev);
-}
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
-       struct i596_private *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned long flags;
-
-       cmd->status = 0;
-       cmd->command |= (CMD_EOL | CMD_INTR);
-       cmd->pa_next = I596_NULL;
-
-       spin_lock_irqsave(&lp->cmd_lock, flags);
-
-       if (lp->cmd_head) {
-               lp->cmd_tail->pa_next = va_to_pa(cmd);
-       } else {
-               lp->cmd_head = cmd;
-               if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
-                       ;
-               lp->scb.pa_cmd = va_to_pa(cmd);
-               lp->scb.command = CUC_START;
-               CA();
-       }
-       lp->cmd_tail = cmd;
-       lp->cmd_backlog++;
-
-       lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
-       spin_unlock_irqrestore(&lp->cmd_lock, flags);
-
-       if (lp->cmd_backlog > 16) {
-               int tickssofar = jiffies - lp->last_cmd;
-               if (tickssofar < HZ/4)
-                       return;
-
-               printk(KERN_WARNING "%s: command unit timed out, status resetting.\n", dev->name);
-               i596_reset(dev, lp, ioaddr);
-       }
-}
-
-static int i596_open(struct net_device *dev)
-{
-       int i;
-
-       i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev);
-       if (i) {
-               printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
-               return i;
-       }
-
-       if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
-               printk(KERN_ERR "%s: only able to allocate %d receive buffers\n", dev->name, i);
-
-       if (i < 4) {
-               free_irq(dev->irq, dev);
-               return -EAGAIN;
-       }
-       netif_start_queue(dev);
-       init_i596(dev);
-       return 0;                       /* Always succeed */
-}
-
-static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
-       struct tx_cmd *tx_cmd;
-       short length;
-
-       length = skb->len;
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-
-       tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
-       if (tx_cmd == NULL) {
-               printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
-               dev->stats.tx_dropped++;
-               dev_kfree_skb (skb);
-       } else {
-               struct i596_tbd *tx_cmd_tbd;
-               tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
-               tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
-               tx_cmd_tbd->pa_next = I596_NULL;
-
-               tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
-
-               tx_cmd->pad = 0;
-               tx_cmd->size = 0;
-               tx_cmd_tbd->pad = 0;
-               tx_cmd_tbd->size = (EOF | length);
-
-               tx_cmd_tbd->pa_data = va_to_pa (skb->data);
-               tx_cmd_tbd->skb = skb;
-
-               if (i596_debug & LOG_SRCDST)
-                       print_eth (skb->data);
-
-               i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
-
-               dev->stats.tx_packets++;
-       }
-
-       return NETDEV_TX_OK;
-}
-
-static void
-i596_tx_timeout (struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       /* Transmitter timeout, serious problems. */
-       printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
-       dev->stats.tx_errors++;
-
-       /* Try to restart the adaptor */
-       if (lp->last_restart == dev->stats.tx_packets) {
-               printk ("Resetting board.\n");
-
-               /* Shutdown and restart */
-               i596_reset (dev, lp, ioaddr);
-       } else {
-               /* Issue a channel attention signal */
-               printk ("Kicking board.\n");
-               lp->scb.command = (CUC_START | RX_START);
-               CA();
-               lp->last_restart = dev->stats.tx_packets;
-       }
-       netif_wake_queue(dev);
-}
-
-static void print_eth(char *add)
-{
-       int i;
-
-       printk ("Dest  ");
-       for (i = 0; i < 6; i++)
-               printk(" %2.2X", (unsigned char) add[i]);
-       printk ("\n");
-
-       printk ("Source");
-       for (i = 0; i < 6; i++)
-               printk(" %2.2X", (unsigned char) add[i+6]);
-       printk ("\n");
-
-       printk ("type %2.2X%2.2X\n",
-               (unsigned char) add[12], (unsigned char) add[13]);
-}
-
-static const struct net_device_ops i596_netdev_ops = {
-       .ndo_open               = i596_open,
-       .ndo_stop               = i596_close,
-       .ndo_start_xmit         = i596_start_xmit,
-       .ndo_set_rx_mode        = set_multicast_list,
-       .ndo_tx_timeout         = i596_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init lp486e_probe(struct net_device *dev) {
-       struct i596_private *lp;
-       unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
-       unsigned char *bios;
-       int i, j;
-       int ret = -ENOMEM;
-       static int probed;
-
-       if (probed)
-               return -ENODEV;
-       probed++;
-
-       if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
-               printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
-               return -EBUSY;
-       }
-
-       lp = netdev_priv(dev);
-       spin_lock_init(&lp->cmd_lock);
-
-       /*
-        * Do we really have this thing?
-        */
-       if (i596_scp_setup(dev)) {
-               ret = -ENODEV;
-               goto err_out_kfree;
-       }
-
-       dev->base_addr = IOADDR;
-       dev->irq = IRQ;
-
-
-       /*
-        * How do we find the ethernet address? I don't know.
-        * One possibility is to look at the EISA configuration area
-        * [0xe8000-0xe9fff]. This contains the ethernet address
-        * but not at a fixed address - things depend on setup options.
-        *
-        * If we find no address, or the wrong address, use
-        *   ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
-        * with the value found in the BIOS setup.
-        */
-       bios = bus_to_virt(0xe8000);
-       for (j = 0; j < 0x2000; j++) {
-               if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
-                       printk("%s: maybe address at BIOS 0x%x:",
-                              dev->name, 0xe8000+j);
-                       for (i = 0; i < 6; i++) {
-                               eth_addr[i] = bios[i+j];
-                               printk(" %2.2X", eth_addr[i]);
-                       }
-                       printk("\n");
-               }
-       }
-
-       printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
-              dev->name, dev->base_addr, dev->irq);
-       for (i = 0; i < 6; i++)
-               printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
-       printk("\n");
-
-       /* The LP486E-specific entries in the device structure. */
-       dev->netdev_ops = &i596_netdev_ops;
-       dev->watchdog_timeo = 5*HZ;
-
-#if 0
-       /* selftest reports 0x320925ae - don't know what that means */
-       i596_port_do(dev, PORT_SELFTEST, "selftest");
-       i596_port_do(dev, PORT_DUMP, "dump");
-#endif
-       return 0;
-
-err_out_kfree:
-       release_region(IOADDR, LP486E_TOTAL_SIZE);
-       return ret;
-}
-
-static inline void
-i596_handle_CU_completion(struct net_device *dev,
-                         struct i596_private *lp,
-                         unsigned short status,
-                         unsigned short *ack_cmdp) {
-       struct i596_cmd *cmd;
-       int frames_out = 0;
-       int commands_done = 0;
-       int cmd_val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&lp->cmd_lock, flags);
-       cmd = lp->cmd_head;
-
-       while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
-               cmd = lp->cmd_head;
-
-               lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
-               lp->cmd_backlog--;
-
-               commands_done++;
-               cmd_val = cmd->command & 0x7;
-#if 0
-               printk("finished CU %s command (%d)\n",
-                      CUcmdnames[cmd_val], cmd_val);
-#endif
-               switch (cmd_val) {
-               case CmdTx:
-               {
-                       struct tx_cmd *tx_cmd;
-                       struct i596_tbd *tx_cmd_tbd;
-
-                       tx_cmd = (struct tx_cmd *) cmd;
-                       tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
-                       frames_out++;
-                       if (cmd->status & CMD_STAT_OK) {
-                               if (i596_debug)
-                                       print_eth(pa_to_va(tx_cmd_tbd->pa_data));
-                       } else {
-                               dev->stats.tx_errors++;
-                               if (i596_debug)
-                                       printk("transmission failure:%04x\n",
-                                              cmd->status);
-                               if (cmd->status & 0x0020)
-                                       dev->stats.collisions++;
-                               if (!(cmd->status & 0x0040))
-                                       dev->stats.tx_heartbeat_errors++;
-                               if (cmd->status & 0x0400)
-                                       dev->stats.tx_carrier_errors++;
-                               if (cmd->status & 0x0800)
-                                       dev->stats.collisions++;
-                               if (cmd->status & 0x1000)
-                                       dev->stats.tx_aborted_errors++;
-                       }
-                       dev_kfree_skb_irq(tx_cmd_tbd->skb);
-
-                       cmd->pa_next = I596_NULL;
-                       kfree((unsigned char *)tx_cmd);
-                       netif_wake_queue(dev);
-                       break;
-               }
-
-               case CmdMulticastList:
-                       cmd->pa_next = I596_NULL;
-                       kfree((unsigned char *)cmd);
-                       break;
-
-               case CmdTDR:
-               {
-                       unsigned long status = *((unsigned long *) (cmd + 1));
-                       if (status & 0x8000) {
-                               if (i596_debug)
-                                       printk("%s: link ok.\n", dev->name);
-                       } else {
-                               if (status & 0x4000)
-                                       printk("%s: Transceiver problem.\n",
-                                              dev->name);
-                               if (status & 0x2000)
-                                       printk("%s: Termination problem.\n",
-                                              dev->name);
-                               if (status & 0x1000)
-                                       printk("%s: Short circuit.\n",
-                                              dev->name);
-                               printk("%s: Time %ld.\n",
-                                      dev->name, status & 0x07ff);
-                       }
-               }
-               default:
-                       cmd->pa_next = I596_NULL;
-                       lp->last_cmd = jiffies;
-
-               }
-               barrier();
-       }
-
-       cmd = lp->cmd_head;
-       while (cmd && (cmd != lp->cmd_tail)) {
-               cmd->command &= 0x1fff;
-               cmd = pa_to_va(cmd->pa_next);
-               barrier();
-       }
-
-       if (lp->cmd_head)
-               *ack_cmdp |= CUC_START;
-       lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-       spin_unlock_irqrestore(&lp->cmd_lock, flags);
-}
-
-static irqreturn_t
-i596_interrupt(int irq, void *dev_instance)
-{
-       struct net_device *dev = dev_instance;
-       struct i596_private *lp = netdev_priv(dev);
-       unsigned short status, ack_cmd = 0;
-       int frames_in = 0;
-
-       /*
-        * The 82596 examines the command, performs the required action,
-        * and then clears the SCB command word.
-        */
-       if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
-               ;
-
-       /*
-        * The status word indicates the status of the 82596.
-        * It is modified only by the 82596.
-        *
-        * [So, we must not clear it. I find often status 0xffff,
-        *  which is not one of the values allowed by the docs.]
-        */
-       status = lp->scb.status;
-#if 0
-       if (i596_debug) {
-               printk("%s: i596 interrupt, ", dev->name);
-               i596_out_status(status);
-       }
-#endif
-       /* Impossible, but it happens - perhaps when we get
-          a receive interrupt but scb.pa_rfd is I596_NULL. */
-       if (status == 0xffff) {
-               printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
-               goto out;
-       }
-
-       ack_cmd = (status & STAT_ACK);
-
-       if (status & (STAT_CX | STAT_CNA))
-               i596_handle_CU_completion(dev, lp, status, &ack_cmd);
-
-       if (status & (STAT_FR | STAT_RNR)) {
-               /* Restart the receive unit when it got inactive somehow */
-               if ((status & STAT_RNR) && netif_running(dev))
-                       ack_cmd |= RX_START;
-
-               if (status & STAT_FR) {
-                       frames_in = i596_rx(dev);
-                       if (!frames_in)
-                               printk("receive frame reported, but no frames\n");
-               }
-       }
-
-       /* acknowledge the interrupt */
-       /*
-       if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
-               ack_cmd |= CUC_START;
-       */
-
-       if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
-               ;
-
-       lp->scb.command = ack_cmd;
-
-       CLEAR_INT();
-       CA();
-
- out:
-       return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-
-       netif_stop_queue(dev);
-
-       if (i596_debug)
-               printk("%s: Shutting down ethercard, status was %4.4x.\n",
-                      dev->name, lp->scb.status);
-
-       lp->scb.command = (CUC_ABORT | RX_ABORT);
-       CA();
-
-       i596_cleanup_cmd(dev);
-
-       if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
-               ;
-
-       free_irq(dev->irq, dev);
-       remove_rx_bufs(dev);
-
-       return 0;
-}
-
-/*
-*      Set or clear the multicast filter for this adaptor.
-*/
-
-static void set_multicast_list(struct net_device *dev) {
-       struct i596_private *lp = netdev_priv(dev);
-       struct i596_cmd *cmd;
-
-       if (i596_debug > 1)
-               printk ("%s: set multicast list %d\n",
-                       dev->name, netdev_mc_count(dev));
-
-       if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               char *cp;
-               cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
-                             netdev_mc_count(dev) * 6, GFP_ATOMIC);
-               if (cmd == NULL) {
-                       printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
-                       return;
-               }
-               cmd->command = CmdMulticastList;
-               *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
-               cp = ((char *)(cmd + 1))+2;
-               netdev_for_each_mc_addr(ha, dev) {
-                       memcpy(cp, ha->addr, 6);
-                       cp += 6;
-               }
-               if (i596_debug & LOG_SRCDST)
-                       print_eth (((char *)(cmd + 1)) + 2);
-               i596_add_cmd(dev, cmd);
-       } else {
-               if (lp->set_conf.pa_next != I596_NULL) {
-                       return;
-               }
-               if (netdev_mc_empty(dev) &&
-                   !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
-                       lp->i596_config[8] &= ~0x01;
-               } else {
-                       lp->i596_config[8] |= 0x01;
-               }
-
-               i596_add_cmd(dev, &lp->set_conf);
-       }
-}
-
-MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
-MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
-MODULE_LICENSE("GPL");
-
-static struct net_device *dev_lp486e;
-static int full_duplex;
-static int options;
-static int io = IOADDR;
-static int irq = IRQ;
-
-module_param(debug, int, 0);
-//module_param(max_interrupt_work, int, 0);
-//module_param(reverse_probe, int, 0);
-//module_param(rx_copybreak, int, 0);
-module_param(options, int, 0);
-module_param(full_duplex, int, 0);
-
-static int __init lp486e_init_module(void) {
-       int err;
-       struct net_device *dev = alloc_etherdev(sizeof(struct i596_private));
-       if (!dev)
-               return -ENOMEM;
-
-       dev->irq = irq;
-       dev->base_addr = io;
-       err = lp486e_probe(dev);
-       if (err) {
-               free_netdev(dev);
-               return err;
-       }
-       err = register_netdev(dev);
-       if (err) {
-               release_region(dev->base_addr, LP486E_TOTAL_SIZE);
-               free_netdev(dev);
-               return err;
-       }
-       dev_lp486e = dev;
-       full_duplex = 0;
-       options = 0;
-       return 0;
-}
-
-static void __exit lp486e_cleanup_module(void) {
-       unregister_netdev(dev_lp486e);
-       release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE);
-       free_netdev(dev_lp486e);
-}
-
-module_init(lp486e_init_module);
-module_exit(lp486e_cleanup_module);
diff --git a/drivers/net/ethernet/i825xx/ni52.c b/drivers/net/ethernet/i825xx/ni52.c
deleted file mode 100644 (file)
index 272976e..0000000
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
- * net-3-driver for the NI5210 card (i82586 Ethernet chip)
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
- *    [feel free to mail ....]
- *
- * when using as module: (no autoprobing!)
- *   run with e.g:
- *       insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
- *
- * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
- *
- * If you find a bug, please report me:
- *   The kernel panic output and any kmsg from the ni52 driver
- *   the ni5210-driver-version and the linux-kernel version
- *   how many shared memory (memsize) on the netcard,
- *   bootprom: yes/no, base_addr, mem_start
- *   maybe the ni5210-card revision and the i82586 version
- *
- * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
- *                mem_start: 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,
- *                           0xd8000,0xcc000,0xce000,0xda000,0xdc000
- *
- * sources:
- *   skeleton.c from Donald Becker
- *
- * I have also done a look in the following sources: (mail me if you need them)
- *   crynwr-packet-driver by Russ Nelson
- *   Garret A. Wollman's (fourth) i82586-driver for BSD
- *   (before getting an i82596 (yes 596 not 586) manual, the existing drivers
- *    helped me a lot to understand this tricky chip.)
- *
- * Known Problems:
- *   The internal sysbus seems to be slow. So we often lose packets because of
- *   overruns while receiving from a fast remote host.
- *   This can slow down TCP connections. Maybe the newer ni5210 cards are
- *   better. My experience is, that if a machine sends with more than about
- *   500-600K/s the fifo/sysbus overflows.
- *
- * IMPORTANT NOTE:
- *   On fast networks, it's a (very) good idea to have 16K shared memory. With
- *   8K, we can store only 4 receive frames, so it can (easily) happen that a
- *   remote machine 'overruns' our system.
- *
- * Known i82586/card problems (I'm sure, there are many more!):
- *   Running the NOP-mode, the i82586 sometimes seems to forget to report
- *   every xmit-interrupt until we restart the CU.
- *   Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit
- *   in the RBD-Struct which indicates an end of the RBD queue.
- *   Instead, the RU fetches another (randomly selected and
- *   usually used) RBD and begins to fill it. (Maybe, this happens only if
- *   the last buffer from the previous RFD fits exact into the queue and
- *   the next RFD can't fetch an initial RBD. Anyone knows more? )
- *
- * results from ftp performance tests with Linux 1.2.5
- *   send and receive about 350-400 KByte/s (peak up to 460 kbytes/s)
- *   sending in NOP-mode: peak performance up to 530K/s (but better don't
- *   run this mode)
- */
-
-/*
- * 29.Sept.96: virt_to_bus changes for new memory scheme
- * 19.Feb.96: more Mcast changes, module support (MH)
- *
- * 18.Nov.95: Mcast changes (AC).
- *
- * 23.April.95: fixed(?) receiving problems by configuring a RFD more
- *              than the number of RBD's. Can maybe cause other problems.
- * 18.April.95: Added MODULE support (MH)
- * 17.April.95: MC related changes in init586() and set_multicast_list().
- *              removed use of 'jiffies' in init586() (MH)
- *
- * 19.Sep.94: Added Multicast support (not tested yet) (MH)
- *
- * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
- *            Now, every RFD has exact one RBD. (MH)
- *
- * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
- *
- * 19.Aug.94: changed request_irq() parameter (MH)
- *
- * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
- *
- * 19.July.94: lotsa cleanups .. (MH)
- *
- * 17.July.94: some patches ... verified to run with 1.1.29 (MH)
- *
- * 4.July.94: patches for Linux 1.1.24  (MH)
- *
- * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
- *
- * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff,
- *                             too (MH)
- *
- * < 30.Sep.93: first versions
- */
-
-static int debuglevel; /* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume; /* experimental .. better should be zero */
-static int rfdadd;     /* rfdadd=1 may be better for 8K MEM cards */
-static int fifo = 0x8; /* don't change */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni52.h"
-
-#define DRV_NAME "ni52"
-
-#define DEBUG       /* debug on */
-#define SYSBUSVAL 1 /* 8 Bit */
-
-#define ni_attn586()  { outb(0, dev->base_addr + NI52_ATTENTION); }
-#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); }
-#define ni_disint()   { outb(0, dev->base_addr + NI52_INTDIS); }
-#define ni_enaint()   { outb(0, dev->base_addr + NI52_INTENA); }
-
-#define make32(ptr16) ((void __iomem *)(p->memtop + (short) (ptr16)))
-#define make24(ptr32) ((char __iomem *)(ptr32)) - p->base
-#define make16(ptr32) ((unsigned short) ((char __iomem *)(ptr32)\
-                                       - p->memtop))
-
-/******************* how to calculate the buffers *****************************
-
-  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
-  * --------------- in a different (more stable?) mode. Only in this mode it's
-  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
-  * if you don't know the driver, better do not change these values: */
-
-#define RECV_BUFF_SIZE 1524 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1    /* config for both, 8K and 16K shmem */
-#define NUM_RECV_BUFFS_8  4 /* config for 8K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
-#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
-
-/**************************************************************************/
-
-
-#define NI52_TOTAL_SIZE 16
-#define NI52_ADDR0 0x02
-#define NI52_ADDR1 0x07
-#define NI52_ADDR2 0x01
-
-static int     ni52_probe1(struct net_device *dev, int ioaddr);
-static irqreturn_t ni52_interrupt(int irq, void *dev_id);
-static int     ni52_open(struct net_device *dev);
-static int     ni52_close(struct net_device *dev);
-static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *);
-static struct  net_device_stats *ni52_get_stats(struct net_device *dev);
-static void    set_multicast_list(struct net_device *dev);
-static void    ni52_timeout(struct net_device *dev);
-
-/* helper-functions */
-static int     init586(struct net_device *dev);
-static int     check586(struct net_device *dev, unsigned size);
-static void    alloc586(struct net_device *dev);
-static void    startrecv586(struct net_device *dev);
-static void   __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr);
-static void    ni52_rcv_int(struct net_device *dev);
-static void    ni52_xmt_int(struct net_device *dev);
-static void    ni52_rnr_int(struct net_device *dev);
-
-struct priv {
-       char __iomem *base;
-       char __iomem *mapped;
-       char __iomem *memtop;
-       spinlock_t spinlock;
-       int reset;
-       struct rfd_struct __iomem *rfd_last, *rfd_top, *rfd_first;
-       struct scp_struct __iomem *scp;
-       struct iscp_struct __iomem *iscp;
-       struct scb_struct __iomem *scb;
-       struct tbd_struct __iomem *xmit_buffs[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
-       struct transmit_cmd_struct __iomem *xmit_cmds[2];
-       struct nop_cmd_struct __iomem *nop_cmds[2];
-#else
-       struct transmit_cmd_struct __iomem *xmit_cmds[NUM_XMIT_BUFFS];
-       struct nop_cmd_struct __iomem *nop_cmds[NUM_XMIT_BUFFS];
-#endif
-       int nop_point, num_recv_buffs;
-       char __iomem *xmit_cbuffs[NUM_XMIT_BUFFS];
-       int xmit_count, xmit_last;
-};
-
-/* wait for command with timeout: */
-static void wait_for_scb_cmd(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       int i;
-       for (i = 0; i < 16384; i++) {
-               if (readb(&p->scb->cmd_cuc) == 0)
-                     break;
-               udelay(4);
-               if (i == 16383) {
-                       printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",
-                               dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus));
-                       if (!p->reset) {
-                               p->reset = 1;
-                               ni_reset586();
-                       }
-               }
-       }
-}
-
-static void wait_for_scb_cmd_ruc(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       int i;
-       for (i = 0; i < 16384; i++) {
-               if (readb(&p->scb->cmd_ruc) == 0)
-                       break;
-               udelay(4);
-               if (i == 16383) {
-                       printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",
-                               dev->name, readb(&p->scb->cmd_ruc),
-                               readb(&p->scb->rus));
-                       if (!p->reset) {
-                               p->reset = 1;
-                               ni_reset586();
-                       }
-               }
-       }
-}
-
-static void wait_for_stat_compl(void __iomem *p)
-{
-       struct nop_cmd_struct __iomem *addr = p;
-       int i;
-       for (i = 0; i < 32767; i++) {
-               if (readw(&((addr)->cmd_status)) & STAT_COMPL)
-                       break;
-               udelay(32);
-       }
-}
-
-/**********************************************
- * close device
- */
-static int ni52_close(struct net_device *dev)
-{
-       free_irq(dev->irq, dev);
-       ni_reset586(); /* the hard way to stop the receiver */
-       netif_stop_queue(dev);
-       return 0;
-}
-
-/**********************************************
- * open device
- */
-static int ni52_open(struct net_device *dev)
-{
-       int ret;
-
-       ni_disint();
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       ni_enaint();
-
-       ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev);
-       if (ret) {
-               ni_reset586();
-               return ret;
-       }
-       netif_start_queue(dev);
-       return 0; /* most done by init */
-}
-
-static int check_iscp(struct net_device *dev, void __iomem *addr)
-{
-       struct iscp_struct __iomem *iscp = addr;
-       struct priv *p = netdev_priv(dev);
-       memset_io(iscp, 0, sizeof(struct iscp_struct));
-
-       writel(make24(iscp), &p->scp->iscp);
-       writeb(1, &iscp->busy);
-
-       ni_reset586();
-       ni_attn586();
-       mdelay(32);     /* wait a while... */
-       /* i82586 clears 'busy' after successful init */
-       if (readb(&iscp->busy))
-               return 0;
-       return 1;
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-static int check586(struct net_device *dev, unsigned size)
-{
-       struct priv *p = netdev_priv(dev);
-       int i;
-
-       p->mapped = ioremap(dev->mem_start, size);
-       if (!p->mapped)
-               return 0;
-
-       p->base = p->mapped + size - 0x01000000;
-       p->memtop = p->mapped + size;
-       p->scp = (struct scp_struct __iomem *)(p->base + SCP_DEFAULT_ADDRESS);
-       p->scb  = (struct scb_struct __iomem *) p->mapped;
-       p->iscp = (struct iscp_struct __iomem *)p->scp - 1;
-       memset_io(p->scp, 0, sizeof(struct scp_struct));
-       for (i = 0; i < sizeof(struct scp_struct); i++)
-               /* memory was writeable? */
-               if (readb((char __iomem *)p->scp + i))
-                       goto Enodev;
-       writeb(SYSBUSVAL, &p->scp->sysbus);     /* 1 = 8Bit-Bus, 0 = 16 Bit */
-       if (readb(&p->scp->sysbus) != SYSBUSVAL)
-               goto Enodev;
-
-       if (!check_iscp(dev, p->mapped))
-               goto Enodev;
-       if (!check_iscp(dev, p->iscp))
-               goto Enodev;
-       return 1;
-Enodev:
-       iounmap(p->mapped);
-       return 0;
-}
-
-/******************************************************************
- * set iscp at the right place, called by ni52_probe1 and open586.
- */
-static void alloc586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       ni_reset586();
-       mdelay(32);
-
-       memset_io(p->iscp, 0, sizeof(struct iscp_struct));
-       memset_io(p->scp , 0, sizeof(struct scp_struct));
-
-       writel(make24(p->iscp), &p->scp->iscp);
-       writeb(SYSBUSVAL, &p->scp->sysbus);
-       writew(make16(p->scb), &p->iscp->scb_offset);
-
-       writeb(1, &p->iscp->busy);
-       ni_reset586();
-       ni_attn586();
-
-       mdelay(32);
-
-       if (readb(&p->iscp->busy))
-               printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
-
-       p->reset = 0;
-
-       memset_io(p->scb, 0, sizeof(struct scb_struct));
-}
-
-/* set: io,irq,memstart,memend or set it when calling insmod */
-static int irq = 9;
-static int io = 0x300;
-static long memstart;  /* e.g 0xd0000 */
-static long memend;    /* e.g 0xd4000 */
-
-/**********************************************
- * probe the ni5210-card
- */
-struct net_device * __init ni52_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct priv));
-       static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
-       const int *port;
-       struct priv *p;
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       p = netdev_priv(dev);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-               memstart = dev->mem_start;
-               memend = dev->mem_end;
-       }
-
-       if (io > 0x1ff) {       /* Check a single specified location. */
-               err = ni52_probe1(dev, io);
-       } else if (io > 0) {            /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-               for (port = ports; *port && ni52_probe1(dev, *port) ; port++)
-                       ;
-               if (*port)
-                       goto got_it;
-#ifdef FULL_IO_PROBE
-               for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8)
-                       ;
-               if (io < 0x400)
-                       goto got_it;
-#endif
-               err = -ENODEV;
-       }
-       if (err)
-               goto out;
-got_it:
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       iounmap(p->mapped);
-       release_region(dev->base_addr, NI52_TOTAL_SIZE);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops ni52_netdev_ops = {
-       .ndo_open               = ni52_open,
-       .ndo_stop               = ni52_close,
-       .ndo_get_stats          = ni52_get_stats,
-       .ndo_tx_timeout         = ni52_timeout,
-       .ndo_start_xmit         = ni52_send_packet,
-       .ndo_set_rx_mode        = set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __init ni52_probe1(struct net_device *dev, int ioaddr)
-{
-       int i, size, retval;
-       struct priv *priv = netdev_priv(dev);
-
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-       dev->mem_start = memstart;
-       dev->mem_end = memend;
-
-       spin_lock_init(&priv->spinlock);
-
-       if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
-               return -EBUSY;
-
-       if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
-           !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       for (i = 0; i < ETH_ALEN; i++)
-               dev->dev_addr[i] = inb(dev->base_addr+i);
-
-       if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ||
-           dev->dev_addr[2] != NI52_ADDR2) {
-               retval = -ENODEV;
-               goto out;
-       }
-
-       printk(KERN_INFO "%s: NI5210 found at %#3lx, ",
-                               dev->name, dev->base_addr);
-
-       /*
-        * check (or search) IO-Memory, 8K and 16K
-        */
-#ifdef MODULE
-       size = dev->mem_end - dev->mem_start;
-       if (size != 0x2000 && size != 0x4000) {
-               printk("\n");
-               printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size);
-               retval = -ENODEV;
-               goto out;
-       }
-       if (!check586(dev, size)) {
-               printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size);
-               retval = -ENODEV;
-               goto out;
-       }
-#else
-       if (dev->mem_start != 0) {
-               /* no auto-mem-probe */
-               size = 0x4000; /* check for 16K mem */
-               if (!check586(dev, size)) {
-                       size = 0x2000; /* check for 8K mem */
-                       if (!check586(dev, size)) {
-                               printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start);
-                               retval = -ENODEV;
-                               goto out;
-                       }
-               }
-       } else {
-               static const unsigned long memaddrs[] = {
-                       0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000,
-                       0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0
-               };
-               for (i = 0;; i++) {
-                       if (!memaddrs[i]) {
-                               printk(KERN_ERR "?memprobe, Can't find io-memory!\n");
-                               retval = -ENODEV;
-                               goto out;
-                       }
-                       dev->mem_start = memaddrs[i];
-                       size = 0x2000; /* check for 8K mem */
-                       if (check586(dev, size))
-                               /* 8K-check */
-                               break;
-                       size = 0x4000; /* check for 16K mem */
-                       if (check586(dev, size))
-                               /* 16K-check */
-                               break;
-               }
-       }
-       /* set mem_end showed by 'ifconfig' */
-       dev->mem_end = dev->mem_start + size;
-#endif
-
-       alloc586(dev);
-
-       /* set number of receive-buffs according to memsize */
-       if (size == 0x2000)
-               priv->num_recv_buffs = NUM_RECV_BUFFS_8;
-       else
-               priv->num_recv_buffs = NUM_RECV_BUFFS_16;
-
-       printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ",
-                               dev->mem_start, size);
-
-       if (dev->irq < 2) {
-               unsigned long irq_mask;
-
-               irq_mask = probe_irq_on();
-               ni_reset586();
-               ni_attn586();
-
-               mdelay(20);
-               dev->irq = probe_irq_off(irq_mask);
-               if (!dev->irq) {
-                       printk("?autoirq, Failed to detect IRQ line!\n");
-                       retval = -EAGAIN;
-                       iounmap(priv->mapped);
-                       goto out;
-               }
-               printk("IRQ %d (autodetected).\n", dev->irq);
-       } else {
-               if (dev->irq == 2)
-                       dev->irq = 9;
-               printk("IRQ %d (assigned and not checked!).\n", dev->irq);
-       }
-
-       dev->netdev_ops         = &ni52_netdev_ops;
-       dev->watchdog_timeo     = HZ/20;
-
-       return 0;
-out:
-       release_region(ioaddr, NI52_TOTAL_SIZE);
-       return retval;
-}
-
-/**********************************************
- * init the chip (ni52-interrupt should be disabled?!)
- * needs a correct 'allocated' memory
- */
-
-static int init586(struct net_device *dev)
-{
-       void __iomem *ptr;
-       int i, result = 0;
-       struct priv *p = netdev_priv(dev);
-       struct configure_cmd_struct __iomem *cfg_cmd;
-       struct iasetup_cmd_struct __iomem *ias_cmd;
-       struct tdr_cmd_struct __iomem *tdr_cmd;
-       struct mcsetup_cmd_struct __iomem *mc_cmd;
-       struct netdev_hw_addr *ha;
-       int num_addrs = netdev_mc_count(dev);
-
-       ptr = p->scb + 1;
-
-       cfg_cmd = ptr; /* configure-command */
-       writew(0, &cfg_cmd->cmd_status);
-       writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd);
-       writew(0xFFFF, &cfg_cmd->cmd_link);
-
-       /* number of cfg bytes */
-       writeb(0x0a, &cfg_cmd->byte_cnt);
-       /* fifo-limit (8=tx:32/rx:64) */
-       writeb(fifo, &cfg_cmd->fifo);
-       /* hold or discard bad recv frames (bit 7) */
-       writeb(0x40, &cfg_cmd->sav_bf);
-       /* addr_len |!src_insert |pre-len |loopback */
-       writeb(0x2e, &cfg_cmd->adr_len);
-       writeb(0x00, &cfg_cmd->priority);
-       writeb(0x60, &cfg_cmd->ifs);
-       writeb(0x00, &cfg_cmd->time_low);
-       writeb(0xf2, &cfg_cmd->time_high);
-       writeb(0x00, &cfg_cmd->promisc);
-       if (dev->flags & IFF_ALLMULTI) {
-               int len = ((char __iomem *)p->iscp - (char __iomem *)ptr - 8) / 6;
-               if (num_addrs > len) {
-                       printk(KERN_ERR "%s: switching to promisc. mode\n",
-                               dev->name);
-                       writeb(0x01, &cfg_cmd->promisc);
-               }
-       }
-       if (dev->flags & IFF_PROMISC)
-               writeb(0x01, &cfg_cmd->promisc);
-       writeb(0x00, &cfg_cmd->carr_coll);
-       writew(make16(cfg_cmd), &p->scb->cbl_offset);
-       writeb(0, &p->scb->cmd_ruc);
-
-       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-       ni_attn586();
-
-       wait_for_stat_compl(cfg_cmd);
-
-       if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
-                                                       (STAT_COMPL|STAT_OK)) {
-               printk(KERN_ERR "%s: configure command failed: %x\n",
-                               dev->name, readw(&cfg_cmd->cmd_status));
-               return 1;
-       }
-
-       /*
-        * individual address setup
-        */
-
-       ias_cmd = ptr;
-
-       writew(0, &ias_cmd->cmd_status);
-       writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd);
-       writew(0xffff, &ias_cmd->cmd_link);
-
-       memcpy_toio(&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN);
-
-       writew(make16(ias_cmd), &p->scb->cbl_offset);
-
-       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-       ni_attn586();
-
-       wait_for_stat_compl(ias_cmd);
-
-       if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
-                                                       (STAT_OK|STAT_COMPL)) {
-               printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status));
-               return 1;
-       }
-
-       /*
-        * TDR, wire check .. e.g. no resistor e.t.c
-        */
-
-       tdr_cmd = ptr;
-
-       writew(0, &tdr_cmd->cmd_status);
-       writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd);
-       writew(0xffff, &tdr_cmd->cmd_link);
-       writew(0, &tdr_cmd->status);
-
-       writew(make16(tdr_cmd), &p->scb->cbl_offset);
-       writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-       ni_attn586();
-
-       wait_for_stat_compl(tdr_cmd);
-
-       if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL))
-               printk(KERN_ERR "%s: Problems while running the TDR.\n",
-                               dev->name);
-       else {
-               udelay(16);
-               result = readw(&tdr_cmd->status);
-               writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
-               ni_attn586(); /* ack the interrupts */
-
-               if (result & TDR_LNK_OK)
-                       ;
-               else if (result & TDR_XCVR_PRB)
-                       printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n",
-                               dev->name);
-               else if (result & TDR_ET_OPN)
-                       printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n",
-                               dev->name, result & TDR_TIMEMASK);
-               else if (result & TDR_ET_SRT) {
-                       /* time == 0 -> strange :-) */
-                       if (result & TDR_TIMEMASK)
-                               printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n",
-                                       dev->name, result & TDR_TIMEMASK);
-               } else
-                       printk(KERN_ERR "%s: TDR: Unknown status %04x\n",
-                                               dev->name, result);
-       }
-
-       /*
-        * Multicast setup
-        */
-       if (num_addrs && !(dev->flags & IFF_PROMISC)) {
-               mc_cmd = ptr;
-               writew(0, &mc_cmd->cmd_status);
-               writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd);
-               writew(0xffff, &mc_cmd->cmd_link);
-               writew(num_addrs * 6, &mc_cmd->mc_cnt);
-
-               i = 0;
-               netdev_for_each_mc_addr(ha, dev)
-                       memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
-
-               writew(make16(mc_cmd), &p->scb->cbl_offset);
-               writeb(CUC_START, &p->scb->cmd_cuc);
-               ni_attn586();
-
-               wait_for_stat_compl(mc_cmd);
-
-               if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK))
-                                                != (STAT_COMPL|STAT_OK))
-                       printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name);
-       }
-
-       /*
-        * alloc nop/xmit-cmds
-        */
-#if (NUM_XMIT_BUFFS == 1)
-       for (i = 0; i < 2; i++) {
-               p->nop_cmds[i] = ptr;
-               writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
-               writew(0, &p->nop_cmds[i]->cmd_status);
-               writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
-               ptr = ptr + sizeof(struct nop_cmd_struct);
-       }
-#else
-       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-               p->nop_cmds[i] = ptr;
-               writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
-               writew(0, &p->nop_cmds[i]->cmd_status);
-               writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
-               ptr = ptr + sizeof(struct nop_cmd_struct);
-       }
-#endif
-
-       ptr = alloc_rfa(dev, ptr); /* init receive-frame-area */
-
-       /*
-        * alloc xmit-buffs / init xmit_cmds
-        */
-       for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-               /* Transmit cmd/buff 0 */
-               p->xmit_cmds[i] = ptr;
-               ptr = ptr + sizeof(struct transmit_cmd_struct);
-               p->xmit_cbuffs[i] = ptr; /* char-buffs */
-               ptr = ptr + XMIT_BUFF_SIZE;
-               p->xmit_buffs[i] = ptr; /* TBD */
-               ptr = ptr + sizeof(struct tbd_struct);
-               if ((void __iomem *)ptr > (void __iomem *)p->iscp) {
-                       printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n",
-                               dev->name);
-                       return 1;
-               }
-               memset_io(p->xmit_cmds[i], 0,
-                                       sizeof(struct transmit_cmd_struct));
-               memset_io(p->xmit_buffs[i], 0,
-                                       sizeof(struct tbd_struct));
-               writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]),
-                                       &p->xmit_cmds[i]->cmd_link);
-               writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status);
-               writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd);
-               writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset);
-               writew(0xffff, &p->xmit_buffs[i]->next);
-               writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer);
-       }
-
-       p->xmit_count = 0;
-       p->xmit_last    = 0;
-#ifndef NO_NOPCOMMANDS
-       p->nop_point    = 0;
-#endif
-
-        /*
-               * 'start transmitter'
-               */
-#ifndef NO_NOPCOMMANDS
-       writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset);
-       writeb(CUC_START, &p->scb->cmd_cuc);
-       ni_attn586();
-       wait_for_scb_cmd(dev);
-#else
-       writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link);
-       writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd);
-#endif
-
-       /*
-        * ack. interrupts
-        */
-       writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
-       ni_attn586();
-       udelay(16);
-
-       ni_enaint();
-
-       return 0;
-}
-
-/******************************************************
- * This is a helper routine for ni52_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr)
-{
-       struct rfd_struct __iomem *rfd = ptr;
-       struct rbd_struct __iomem *rbd;
-       int i;
-       struct priv *p = netdev_priv(dev);
-
-       memset_io(rfd, 0,
-               sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
-       p->rfd_first = rfd;
-
-       for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) {
-               writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)),
-                       &rfd[i].next);
-               writew(0xffff, &rfd[i].rbd_offset);
-       }
-       /* RU suspend */
-       writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last);
-
-       ptr = rfd + (p->num_recv_buffs + rfdadd);
-
-       rbd = ptr;
-       ptr = rbd + p->num_recv_buffs;
-
-        /* clr descriptors */
-       memset_io(rbd, 0, sizeof(struct rbd_struct) * (p->num_recv_buffs));
-
-       for (i = 0; i < p->num_recv_buffs; i++) {
-               writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next);
-               writew(RECV_BUFF_SIZE, &rbd[i].size);
-               writel(make24(ptr), &rbd[i].buffer);
-               ptr = ptr + RECV_BUFF_SIZE;
-       }
-       p->rfd_top      = p->rfd_first;
-       p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
-
-       writew(make16(p->rfd_first), &p->scb->rfa_offset);
-       writew(make16(rbd), &p->rfd_first->rbd_offset);
-
-       return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t ni52_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       unsigned int stat;
-       int cnt = 0;
-       struct priv *p;
-
-       p = netdev_priv(dev);
-
-       if (debuglevel > 1)
-               printk("I");
-
-       spin_lock(&p->spinlock);
-
-       wait_for_scb_cmd(dev); /* wait for last command */
-
-       while ((stat = readb(&p->scb->cus) & STAT_MASK)) {
-               writeb(stat, &p->scb->cmd_cuc);
-               ni_attn586();
-
-               if (stat & STAT_FR)      /* received a frame */
-                       ni52_rcv_int(dev);
-
-               if (stat & STAT_RNR) { /* RU went 'not ready' */
-                       printk("(R)");
-                       if (readb(&p->scb->rus) & RU_SUSPEND) {
-                               /* special case: RU_SUSPEND */
-                               wait_for_scb_cmd(dev);
-                               writeb(RUC_RESUME, &p->scb->cmd_ruc);
-                               ni_attn586();
-                               wait_for_scb_cmd_ruc(dev);
-                       } else {
-                               printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",
-                                       dev->name, stat, readb(&p->scb->rus));
-                               ni52_rnr_int(dev);
-                       }
-               }
-
-               /* Command with I-bit set complete */
-               if (stat & STAT_CX)
-                        ni52_xmt_int(dev);
-
-#ifndef NO_NOPCOMMANDS
-               if (stat & STAT_CNA) {  /* CU went 'not ready' */
-                       if (netif_running(dev))
-                               printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n",
-                                       dev->name, stat, readb(&p->scb->cus));
-               }
-#endif
-
-               if (debuglevel > 1)
-                       printk("%d", cnt++);
-
-               /* Wait for ack. (ni52_xmt_int can be faster than ack!!) */
-               wait_for_scb_cmd(dev);
-               if (readb(&p->scb->cmd_cuc)) {   /* timed out? */
-                       printk(KERN_ERR "%s: Acknowledge timed out.\n",
-                               dev->name);
-                       ni_disint();
-                       break;
-               }
-       }
-       spin_unlock(&p->spinlock);
-
-       if (debuglevel > 1)
-               printk("i");
-       return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void ni52_rcv_int(struct net_device *dev)
-{
-       int status, cnt = 0;
-       unsigned short totlen;
-       struct sk_buff *skb;
-       struct rbd_struct __iomem *rbd;
-       struct priv *p = netdev_priv(dev);
-
-       if (debuglevel > 0)
-               printk("R");
-
-       for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) {
-               rbd = make32(readw(&p->rfd_top->rbd_offset));
-               if (status & RFD_OK) { /* frame received without error? */
-                       totlen = readw(&rbd->status);
-                       if (totlen & RBD_LAST) {
-                               /* the first and the last buffer? */
-                               totlen &= RBD_MASK; /* length of this frame */
-                               writew(0x00, &rbd->status);
-                               skb = netdev_alloc_skb(dev, totlen + 2);
-                               if (skb != NULL) {
-                                       skb_reserve(skb, 2);
-                                       skb_put(skb, totlen);
-                                       memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
-                                       skb->protocol = eth_type_trans(skb, dev);
-                                       netif_rx(skb);
-                                       dev->stats.rx_packets++;
-                                       dev->stats.rx_bytes += totlen;
-                               } else
-                                       dev->stats.rx_dropped++;
-                       } else {
-                               int rstat;
-                                /* free all RBD's until RBD_LAST is set */
-                               totlen = 0;
-                               while (!((rstat = readw(&rbd->status)) & RBD_LAST)) {
-                                       totlen += rstat & RBD_MASK;
-                                       if (!rstat) {
-                                               printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name);
-                                               break;
-                                       }
-                                       writew(0, &rbd->status);
-                                       rbd = make32(readw(&rbd->next));
-                               }
-                               totlen += rstat & RBD_MASK;
-                               writew(0, &rbd->status);
-                               printk(KERN_ERR "%s: received oversized frame! length: %d\n",
-                                       dev->name, totlen);
-                               dev->stats.rx_dropped++;
-                        }
-               } else {/* frame !(ok), only with 'save-bad-frames' */
-                       printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
-                               dev->name, status);
-                       dev->stats.rx_errors++;
-               }
-               writeb(0, &p->rfd_top->stat_high);
-               writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
-               writew(0xffff, &p->rfd_top->rbd_offset);
-               writeb(0, &p->rfd_last->last);  /* delete RFD_SUSP      */
-               p->rfd_last = p->rfd_top;
-               p->rfd_top = make32(readw(&p->rfd_top->next)); /* step to next RFD */
-               writew(make16(p->rfd_top), &p->scb->rfa_offset);
-
-               if (debuglevel > 0)
-                       printk("%d", cnt++);
-       }
-
-       if (automatic_resume) {
-               wait_for_scb_cmd(dev);
-               writeb(RUC_RESUME, &p->scb->cmd_ruc);
-               ni_attn586();
-               wait_for_scb_cmd_ruc(dev);
-       }
-
-#ifdef WAIT_4_BUSY
-       {
-               int i;
-               for (i = 0; i < 1024; i++) {
-                       if (p->rfd_top->status)
-                               break;
-                       udelay(16);
-                       if (i == 1023)
-                               printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name);
-               }
-       }
-#endif
-       if (debuglevel > 0)
-               printk("r");
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void ni52_rnr_int(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       dev->stats.rx_errors++;
-
-       wait_for_scb_cmd(dev);          /* wait for the last cmd, WAIT_4_FULLSTAT?? */
-       writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
-       ni_attn586();
-       wait_for_scb_cmd_ruc(dev);              /* wait for accept cmd. */
-
-       alloc_rfa(dev, p->rfd_first);
-       /* maybe add a check here, before restarting the RU */
-       startrecv586(dev); /* restart RU */
-
-       printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n",
-               dev->name, readb(&p->scb->rus));
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void ni52_xmt_int(struct net_device *dev)
-{
-       int status;
-       struct priv *p = netdev_priv(dev);
-
-       if (debuglevel > 0)
-               printk("X");
-
-       status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status);
-       if (!(status & STAT_COMPL))
-               printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
-
-       if (status & STAT_OK) {
-               dev->stats.tx_packets++;
-               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
-       } else {
-               dev->stats.tx_errors++;
-               if (status & TCMD_LATECOLL) {
-                       printk(KERN_ERR "%s: late collision detected.\n",
-                               dev->name);
-                       dev->stats.collisions++;
-               } else if (status & TCMD_NOCARRIER) {
-                       dev->stats.tx_carrier_errors++;
-                       printk(KERN_ERR "%s: no carrier detected.\n",
-                               dev->name);
-               } else if (status & TCMD_LOSTCTS)
-                       printk(KERN_ERR "%s: loss of CTS detected.\n",
-                               dev->name);
-               else if (status & TCMD_UNDERRUN) {
-                       dev->stats.tx_fifo_errors++;
-                       printk(KERN_ERR "%s: DMA underrun detected.\n",
-                               dev->name);
-               } else if (status & TCMD_MAXCOLL) {
-                       printk(KERN_ERR "%s: Max. collisions exceeded.\n",
-                               dev->name);
-                       dev->stats.collisions += 16;
-               }
-       }
-#if (NUM_XMIT_BUFFS > 1)
-       if ((++p->xmit_last) == NUM_XMIT_BUFFS)
-               p->xmit_last = 0;
-#endif
-       netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-
-       wait_for_scb_cmd(dev);
-       wait_for_scb_cmd_ruc(dev);
-       writew(make16(p->rfd_first), &p->scb->rfa_offset);
-       writeb(RUC_START, &p->scb->cmd_ruc);
-       ni_attn586();           /* start cmd. */
-       wait_for_scb_cmd_ruc(dev);
-       /* wait for accept cmd. (no timeout!!) */
-}
-
-static void ni52_timeout(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-#ifndef NO_NOPCOMMANDS
-       if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
-               netif_wake_queue(dev);
-#ifdef DEBUG
-               printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n",
-                       dev->name);
-               printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n",
-                       dev->name, (int)p->xmit_cmds[0]->cmd_status,
-                       readw(&p->nop_cmds[0]->cmd_status),
-                       readw(&p->nop_cmds[1]->cmd_status),
-                       p->nop_point);
-#endif
-               writeb(CUC_ABORT, &p->scb->cmd_cuc);
-               ni_attn586();
-               wait_for_scb_cmd(dev);
-               writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset);
-               writeb(CUC_START, &p->scb->cmd_cuc);
-               ni_attn586();
-               wait_for_scb_cmd(dev);
-               dev->trans_start = jiffies; /* prevent tx timeout */
-               return 0;
-       }
-#endif
-       {
-#ifdef DEBUG
-               printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n",
-                               dev->name, readb(&p->scb->cus));
-               printk(KERN_ERR "%s: command-stats: %04x %04x\n",
-                               dev->name,
-                               readw(&p->xmit_cmds[0]->cmd_status),
-                               readw(&p->xmit_cmds[1]->cmd_status));
-               printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n",
-                               dev->name);
-#endif
-               ni52_close(dev);
-               ni52_open(dev);
-       }
-       dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/******************************************************
- * send frame
- */
-
-static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev)
-{
-       int len, i;
-#ifndef NO_NOPCOMMANDS
-       int next_nop;
-#endif
-       struct priv *p = netdev_priv(dev);
-
-       if (skb->len > XMIT_BUFF_SIZE) {
-               printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
-               return NETDEV_TX_OK;
-       }
-
-       netif_stop_queue(dev);
-
-       memcpy_toio(p->xmit_cbuffs[p->xmit_count], skb->data, skb->len);
-       len = skb->len;
-       if (len < ETH_ZLEN) {
-               len = ETH_ZLEN;
-               memset_io(p->xmit_cbuffs[p->xmit_count]+skb->len, 0,
-                                                       len - skb->len);
-       }
-
-#if (NUM_XMIT_BUFFS == 1)
-#      ifdef NO_NOPCOMMANDS
-
-#ifdef DEBUG
-       if (readb(&p->scb->cus) & CU_ACTIVE) {
-               printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name);
-               printk(KERN_ERR "%s: stat: %04x %04x\n",
-                               dev->name, readb(&p->scb->cus),
-                               readw(&p->xmit_cmds[0]->cmd_status));
-       }
-#endif
-       writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
-       for (i = 0; i < 16; i++) {
-               writew(0, &p->xmit_cmds[0]->cmd_status);
-               wait_for_scb_cmd(dev);
-               if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND)
-                       writeb(CUC_RESUME, &p->scb->cmd_cuc);
-               else {
-                       writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset);
-                       writeb(CUC_START, &p->scb->cmd_cuc);
-               }
-               ni_attn586();
-               if (!i)
-                       dev_kfree_skb(skb);
-               wait_for_scb_cmd(dev);
-               /* test it, because CU sometimes doesn't start immediately */
-               if (readb(&p->scb->cus) & CU_ACTIVE)
-                       break;
-               if (readw(&p->xmit_cmds[0]->cmd_status))
-                       break;
-               if (i == 15)
-                       printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
-       }
-#      else
-       next_nop = (p->nop_point + 1) & 0x1;
-       writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
-       writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link);
-       writew(make16(p->nop_cmds[next_nop]),
-                               &p->nop_cmds[next_nop]->cmd_link);
-       writew(0, &p->xmit_cmds[0]->cmd_status);
-       writew(0, &p->nop_cmds[next_nop]->cmd_status);
-
-       writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
-       p->nop_point = next_nop;
-       dev_kfree_skb(skb);
-#      endif
-#else
-       writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size);
-       next_nop = p->xmit_count + 1
-       if (next_nop == NUM_XMIT_BUFFS)
-               next_nop = 0;
-       writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status);
-       /* linkpointer of xmit-command already points to next nop cmd */
-       writew(make16(p->nop_cmds[next_nop]),
-                               &p->nop_cmds[next_nop]->cmd_link);
-       writew(0, &p->nop_cmds[next_nop]->cmd_status);
-       writew(make16(p->xmit_cmds[p->xmit_count]),
-                               &p->nop_cmds[p->xmit_count]->cmd_link);
-       p->xmit_count = next_nop;
-       {
-               unsigned long flags;
-               spin_lock_irqsave(&p->spinlock);
-               if (p->xmit_count != p->xmit_last)
-                       netif_wake_queue(dev);
-               spin_unlock_irqrestore(&p->spinlock);
-       }
-       dev_kfree_skb(skb);
-#endif
-       return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *ni52_get_stats(struct net_device *dev)
-{
-       struct priv *p = netdev_priv(dev);
-       unsigned short crc, aln, rsc, ovrn;
-
-       /* Get error-statistics from the ni82586 */
-       crc = readw(&p->scb->crc_errs);
-       writew(0, &p->scb->crc_errs);
-       aln = readw(&p->scb->aln_errs);
-       writew(0, &p->scb->aln_errs);
-       rsc = readw(&p->scb->rsc_errs);
-       writew(0, &p->scb->rsc_errs);
-       ovrn = readw(&p->scb->ovrn_errs);
-       writew(0, &p->scb->ovrn_errs);
-
-       dev->stats.rx_crc_errors += crc;
-       dev->stats.rx_fifo_errors += ovrn;
-       dev->stats.rx_frame_errors += aln;
-       dev->stats.rx_dropped += rsc;
-
-       return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       ni_disint();
-       alloc586(dev);
-       init586(dev);
-       startrecv586(dev);
-       ni_enaint();
-       netif_wake_queue(dev);
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni52;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(memstart, long, 0);
-module_param(memend, long, 0);
-MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
-MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
-MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
-MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
-
-int __init init_module(void)
-{
-       if (io <= 0x0 || !memend || !memstart || irq < 2) {
-               printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n");
-               printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
-               return -ENODEV;
-       }
-       dev_ni52 = ni52_probe(-1);
-       if (IS_ERR(dev_ni52))
-               return PTR_ERR(dev_ni52);
-       return 0;
-}
-
-void __exit cleanup_module(void)
-{
-       struct priv *p = netdev_priv(dev_ni52);
-       unregister_netdev(dev_ni52);
-       iounmap(p->mapped);
-       release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
-       free_netdev(dev_ni52);
-}
-#endif /* MODULE */
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/ni52.h b/drivers/net/ethernet/i825xx/ni52.h
deleted file mode 100644 (file)
index 0a03b28..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
- *
- * I have done a look in the following sources:
- *   crynwr-packet-driver by Russ Nelson
- *   Garret A. Wollman's i82586-driver for BSD
- */
-
-
-#define NI52_RESET     0  /* writing to this address, resets the i82586 */
-#define NI52_ATTENTION 1  /* channel attention, kick the 586 */
-#define NI52_TENA      3  /* 2-5 possibly wrong, Xmit enable */
-#define NI52_TDIS      2  /* Xmit disable */
-#define NI52_INTENA    5  /* Interrupt enable */
-#define NI52_INTDIS    4  /* Interrupt disable */
-#define NI52_MAGIC1    6  /* dunno exact function */
-#define NI52_MAGIC2    7  /* dunno exact function */
-
-#define NI52_MAGICVAL1 0x00  /* magic-values for ni5210 card */
-#define NI52_MAGICVAL2 0x55
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
-       u16 zero_dum0;  /* has to be zero */
-       u8 sysbus;      /* 0=16Bit,1=8Bit */
-       u8 zero_dum1;   /* has to be zero for 586 */
-       u16 zero_dum2;
-       u16 zero_dum3;
-       u32 iscp;               /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
-       u8 busy;          /* 586 clears after successful init */
-       u8 zero_dummy;    /* has to be zero */
-       u16 scb_offset;    /* pointeroffset to the scb_base */
-       u32 scb_base;      /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
-       u8 rus;
-       u8 cus;
-       u8 cmd_ruc;        /* command word: RU part */
-       u8 cmd_cuc;        /* command word: CU part & ACK */
-       u16 cbl_offset;    /* pointeroffset, command block list */
-       u16 rfa_offset;    /* pointeroffset, receive frame area */
-       u16 crc_errs;      /* CRC-Error counter */
-       u16 aln_errs;      /* alignmenterror counter */
-       u16 rsc_errs;      /* Resourceerror counter */
-       u16 ovrn_errs;     /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK       0x0070  /* mask for RU commands */
-#define RUC_NOP                0x0000  /* NOP-command */
-#define RUC_START      0x0010  /* start RU */
-#define RUC_RESUME     0x0020  /* resume RU after suspend */
-#define RUC_SUSPEND    0x0030  /* suspend RU */
-#define RUC_ABORT      0x0040  /* abort receiver operation immediately */
-
-#define CUC_MASK        0x07  /* mask for CU command */
-#define CUC_NOP         0x00  /* NOP-command */
-#define CUC_START       0x01  /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME      0x02  /* resume after suspend */
-#define CUC_SUSPEND     0x03  /* Suspend CU */
-#define CUC_ABORT       0x04  /* abort command operation immediately */
-
-#define ACK_MASK        0xf0  /* mask for ACK command */
-#define ACK_CX          0x80  /* acknowledges STAT_CX */
-#define ACK_FR          0x40  /* ack. STAT_FR */
-#define ACK_CNA         0x20  /* ack. STAT_CNA */
-#define ACK_RNR         0x10  /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK       0xf0  /* mask for cause of interrupt */
-#define STAT_CX         0x80  /* CU finished cmd with its I bit set */
-#define STAT_FR         0x40  /* RU finished receiving a frame */
-#define STAT_CNA        0x20  /* CU left active state */
-#define STAT_RNR        0x10  /* RU left ready state */
-
-#define CU_STATUS       0x7   /* CU status, 0=idle */
-#define CU_SUSPEND      0x1   /* CU is suspended */
-#define CU_ACTIVE       0x2   /* CU is active */
-
-#define RU_STATUS      0x70    /* RU status, 0=idle */
-#define RU_SUSPEND     0x10    /* RU suspended */
-#define RU_NOSPACE     0x20    /* RU no resources */
-#define RU_READY       0x40    /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
-       u8  stat_low;   /* status word */
-       u8  stat_high;  /* status word */
-       u8  rfd_sf;     /* 82596 mode only */
-       u8  last;               /* Bit15,Last Frame on List / Bit14,suspend */
-       u16 next;               /* linkoffset to next RFD */
-       u16 rbd_offset; /* pointeroffset to RBD-buffer */
-       u8  dest[6];    /* ethernet-address, destination */
-       u8  source[6];  /* ethernet-address, source */
-       u16 length;     /* 802.3 frame-length */
-       u16 zero_dummy; /* dummy */
-};
-
-#define RFD_LAST     0x80      /* last: last rfd in the list */
-#define RFD_SUSP     0x40      /* last: suspend RU after  */
-#define RFD_COMPL    0x80
-#define RFD_OK       0x20
-#define RFD_BUSY     0x40
-#define RFD_ERR_LEN  0x10     /* Length error (if enabled length-checking */
-#define RFD_ERR_CRC  0x08     /* CRC error */
-#define RFD_ERR_ALGN 0x04     /* Alignment error */
-#define RFD_ERR_RNR  0x02     /* status: receiver out of resources */
-#define RFD_ERR_OVR  0x01     /* DMA Overrun! */
-
-#define RFD_ERR_FTS  0x0080    /* Frame to short */
-#define RFD_ERR_NEOP 0x0040    /* No EOP flag (for bitstuffing only) */
-#define RFD_ERR_TRUN 0x0020    /* (82596 only/SF mode) indicates truncated frame */
-#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA (only 82596) */
-#define RFD_COLLDET  0x0001    /* Detected collision during reception */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
-       u16 status;     /* status word,number of used bytes in buff */
-       u16 next;               /* pointeroffset to next RBD */
-       u32 buffer;     /* receive buffer address pointer */
-       u16 size;               /* size of this buffer */
-       u16 zero_dummy;    /* dummy */
-};
-
-#define RBD_LAST       0x8000  /* last buffer */
-#define RBD_USED       0x4000  /* this buffer has data */
-#define RBD_MASK       0x3fff  /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL   0x8000    /* status: frame/command is complete */
-#define STAT_BUSY    0x4000    /* status: frame/command is busy */
-#define STAT_OK      0x2000    /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP                0x0000  /* NOP */
-#define CMD_IASETUP    0x0001  /* initial address setup command */
-#define CMD_CONFIGURE  0x0002  /* configure command */
-#define CMD_MCSETUP    0x0003  /* MC setup command */
-#define CMD_XMIT       0x0004  /* transmit command */
-#define CMD_TDR                0x0005  /* time domain reflectometer (TDR) command */
-#define CMD_DUMP       0x0006  /* dump command */
-#define CMD_DIAGNOSE   0x0007  /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST       0x8000  /* indicates last command in the CBL */
-#define CMD_SUSPEND    0x4000  /* suspend CU after this CB */
-#define CMD_INT                0x2000  /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
-       u16 cmd_status; /* status of this command */
-       u16 cmd_cmd;       /* the command itself (+bits) */
-       u16 cmd_link;      /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u8  iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u8  byte_cnt;   /* size of the config-cmd */
-       u8  fifo;       /* fifo/recv monitor */
-       u8  sav_bf;     /* save bad frames (bit7=1)*/
-       u8  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
-       u8  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
-       u8  ifs;        /* inter frame spacing */
-       u8  time_low;   /* slot time low */
-       u8  time_high;  /* slot time high(0-2) and max. retries(4-7) */
-       u8  promisc;    /* promisc-mode(0) , et al (1-7) */
-       u8  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
-       u8  fram_len;   /* minimal frame len */
-       u8  dummy;           /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 mc_cnt;             /* number of bytes in the MC-List */
-       u8  mc_list[0][6];      /* pointer to 6 bytes entries */
-};
-
-/*
- * DUMP command
- */
-struct dump_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 dump_offset;    /* pointeroffset to DUMP space */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 tbd_offset; /* pointeroffset to TBD */
-       u8  dest[6];       /* destination address of the frame */
-       u16 length;     /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK     0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL     0x0020
-#define TCMD_HEARTBEAT   0x0040
-#define TCMD_DEFERRED    0x0080
-#define TCMD_UNDERRUN    0x0100
-#define TCMD_LOSTCTS     0x0200
-#define TCMD_NOCARRIER   0x0400
-#define TCMD_LATECOLL    0x0800
-
-struct tdr_cmd_struct
-{
-       u16 cmd_status;
-       u16 cmd_cmd;
-       u16 cmd_link;
-       u16 status;
-};
-
-#define TDR_LNK_OK     0x8000  /* No link problem identified */
-#define TDR_XCVR_PRB   0x4000  /* indicates a transceiver problem */
-#define TDR_ET_OPN     0x2000  /* open, no correct termination */
-#define TDR_ET_SRT     0x1000  /* TDR detected a short circuit */
-#define TDR_TIMEMASK   0x07ff  /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
-       u16 size;               /* size + EOF-Flag(15) */
-       u16 next;          /* pointeroffset to next TBD */
-       u32 buffer;        /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
-
-
-
-
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c
deleted file mode 100644 (file)
index c9479e0..0000000
+++ /dev/null
@@ -1,928 +0,0 @@
-/* znet.c: An Zenith Z-Note ethernet driver for linux. */
-
-/*
-       Written by Donald Becker.
-
-       The author may be reached as becker@scyld.com.
-       This driver is based on the Linux skeleton driver.  The copyright of the
-       skeleton driver is held by the United States Government, as represented
-       by DIRNSA, and it is released under the GPL.
-
-       Thanks to Mike Hollick for alpha testing and suggestions.
-
-  References:
-          The Crynwr packet driver.
-
-         "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
-         Intel Microcommunications Databook, Vol. 1, 1990.
-    As usual with Intel, the documentation is incomplete and inaccurate.
-       I had to read the Crynwr packet driver to figure out how to actually
-       use the i82593, and guess at what register bits matched the loosely
-       related i82586.
-
-                                       Theory of Operation
-
-       The i82593 used in the Zenith Z-Note series operates using two(!) slave
-       DMA     channels, one interrupt, and one 8-bit I/O port.
-
-       While there     several ways to configure '593 DMA system, I chose the one
-       that seemed commensurate with the highest system performance in the face
-       of moderate interrupt latency: Both DMA channels are configured as
-       recirculating ring buffers, with one channel (#0) dedicated to Rx and
-       the other channel (#1) to Tx and configuration.  (Note that this is
-       different than the Crynwr driver, where the Tx DMA channel is initialized
-       before each operation.  That approach simplifies operation and Tx error
-       recovery, but requires additional I/O in normal operation and precludes
-       transmit buffer chaining.)
-
-       Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE.  This provides
-       a reasonable ring size for Rx, while simplifying DMA buffer allocation --
-       DMA buffers must not cross a 128K boundary.  (In truth the size selection
-       was influenced by my lack of '593 documentation.  I thus was constrained
-       to use the Crynwr '593 initialization table, which sets the Rx ring size
-       to 8K.)
-
-       Despite my usual low opinion about Intel-designed parts, I must admit
-       that the bulk data handling of the i82593 is a good design for
-       an integrated system, like a laptop, where using two slave DMA channels
-       doesn't pose a problem.  I still take issue with using only a single I/O
-       port.  In the same controlled environment there are essentially no
-       limitations on I/O space, and using multiple locations would eliminate
-       the     need for multiple operations when looking at status registers,
-       setting the Rx ring boundary, or switching to promiscuous mode.
-
-       I also question Zenith's selection of the '593: one of the advertised
-       advantages of earlier Intel parts was that if you figured out the magic
-       initialization incantation you could use the same part on many different
-       network types.  Zenith's use of the "FriendlyNet" (sic) connector rather
-       than an on-board transceiver leads me to believe that they were planning
-       to take advantage of this.  But, uhmmm, the '593 omits all but ethernet
-       functionality from the serial subsystem.
- */
-
-/* 10/2002
-
-   o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
-
-   - Removed strange DMA snooping in znet_sent_packet, which lead to
-     TX buffer corruption on my laptop.
-   - Use init_etherdev stuff.
-   - Use kmalloc-ed DMA buffers.
-   - Use as few global variables as possible.
-   - Use proper resources management.
-   - Use wireless/i82593.h as much as possible (structure, constants)
-   - Compiles as module or build-in.
-   - Now survives unplugging/replugging cable.
-
-   Some code was taken from wavelan_cs.
-
-   Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
-   anything else. Testers (and detailed bug reports) are welcome :-).
-
-   o TODO :
-
-   - Properly handle multicast
-   - Understand why some traffic patterns add a 1s latency...
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/i82593.h>
-
-static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
-
-#ifndef ZNET_DEBUG
-#define ZNET_DEBUG 1
-#endif
-static unsigned int znet_debug = ZNET_DEBUG;
-module_param (znet_debug, int, 0);
-MODULE_PARM_DESC (znet_debug, "ZNet debug level");
-MODULE_LICENSE("GPL");
-
-/* The DMA modes we need aren't in <dma.h>. */
-#define DMA_RX_MODE            0x14    /* Auto init, I/O to mem, ++, demand. */
-#define DMA_TX_MODE            0x18    /* Auto init, Mem to I/O, ++, demand. */
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
-#define RX_BUF_SIZE 8192
-#define TX_BUF_SIZE 8192
-#define DMA_BUF_SIZE (RX_BUF_SIZE + 16)        /* 8k + 16 bytes for trailers */
-
-#define TX_TIMEOUT     (HZ/10)
-
-struct znet_private {
-       int rx_dma, tx_dma;
-       spinlock_t lock;
-       short sia_base, sia_size, io_size;
-       struct i82593_conf_block i593_init;
-       /* The starting, current, and end pointers for the packet buffers. */
-       ushort *rx_start, *rx_cur, *rx_end;
-       ushort *tx_start, *tx_cur, *tx_end;
-       ushort tx_buf_len;                      /* Tx buffer length, in words. */
-};
-
-/* Only one can be built-in;-> */
-static struct net_device *znet_dev;
-
-#define NETIDBLK_MAGIC         "NETIDBLK"
-#define NETIDBLK_MAGIC_SIZE    8
-
-struct netidblk {
-       char magic[NETIDBLK_MAGIC_SIZE];        /* The magic number (string) "NETIDBLK" */
-       unsigned char netid[8]; /* The physical station address */
-       char nettype, globalopt;
-       char vendor[8];         /* The machine vendor and product name. */
-       char product[8];
-       char irq1, irq2;                /* Interrupts, only one is currently used.      */
-       char dma1, dma2;
-       short dma_mem_misc[8];          /* DMA buffer locations (unused in Linux). */
-       short iobase1, iosize1;
-       short iobase2, iosize2;         /* Second iobase unused. */
-       char driver_options;                    /* Misc. bits */
-       char pad;
-};
-
-static int     znet_open(struct net_device *dev);
-static netdev_tx_t znet_send_packet(struct sk_buff *skb,
-                                   struct net_device *dev);
-static irqreturn_t znet_interrupt(int irq, void *dev_id);
-static void    znet_rx(struct net_device *dev);
-static int     znet_close(struct net_device *dev);
-static void hardware_init(struct net_device *dev);
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
-static void znet_tx_timeout (struct net_device *dev);
-
-/* Request needed resources */
-static int znet_request_resources (struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-
-       if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
-               goto failed;
-       if (request_dma (znet->rx_dma, "ZNet rx"))
-               goto free_irq;
-       if (request_dma (znet->tx_dma, "ZNet tx"))
-               goto free_rx_dma;
-       if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
-               goto free_tx_dma;
-       if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
-               goto free_sia;
-
-       return 0;                               /* Happy ! */
-
- free_sia:
-       release_region (znet->sia_base, znet->sia_size);
- free_tx_dma:
-       free_dma (znet->tx_dma);
- free_rx_dma:
-       free_dma (znet->rx_dma);
- free_irq:
-       free_irq (dev->irq, dev);
- failed:
-       return -1;
-}
-
-static void znet_release_resources (struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-
-       release_region (znet->sia_base, znet->sia_size);
-       release_region (dev->base_addr, znet->io_size);
-       free_dma (znet->tx_dma);
-       free_dma (znet->rx_dma);
-       free_irq (dev->irq, dev);
-}
-
-/* Keep the magical SIA stuff in a single function... */
-static void znet_transceiver_power (struct net_device *dev, int on)
-{
-       struct znet_private *znet = netdev_priv(dev);
-       unsigned char v;
-
-       /* Turn on/off the 82501 SIA, using zenith-specific magic. */
-       /* Select LAN control register */
-       outb(0x10, znet->sia_base);
-
-       if (on)
-               v = inb(znet->sia_base + 1) | 0x84;
-       else
-               v = inb(znet->sia_base + 1) & ~0x84;
-
-       outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
-}
-
-/* Init the i82593, with current promisc/mcast configuration.
-   Also used from hardware_init. */
-static void znet_set_multicast_list (struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-       short ioaddr = dev->base_addr;
-       struct i82593_conf_block *cfblk = &znet->i593_init;
-
-       memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
-
-        /* The configuration block.  What an undocumented nightmare.
-          The first set of values are those suggested (without explanation)
-          for ethernet in the Intel 82586 databook.  The rest appear to be
-          completely undocumented, except for cryptic notes in the Crynwr
-          packet driver.  This driver uses the Crynwr values verbatim. */
-
-       /* maz : Rewritten to take advantage of the wanvelan includes.
-          At least we have names, not just blind values */
-
-       /* Byte 0 */
-       cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
-       cfblk->forgnesi = 0;    /* 0=82C501, 1=AMD7992B compatibility */
-       cfblk->fifo_32 = 1;
-       cfblk->d6mod = 0;       /* Run in i82593 advanced mode */
-       cfblk->throttle_enb = 1;
-
-       /* Byte 1 */
-       cfblk->throttle = 8;    /* Continuous w/interrupts, 128-clock DMA. */
-       cfblk->cntrxint = 0;    /* enable continuous mode receive interrupts */
-       cfblk->contin = 1;      /* enable continuous mode */
-
-       /* Byte 2 */
-       cfblk->addr_len = ETH_ALEN;
-       cfblk->acloc = 1;       /* Disable source addr insertion by i82593 */
-       cfblk->preamb_len = 2;  /* 8 bytes preamble */
-       cfblk->loopback = 0;    /* Loopback off */
-
-       /* Byte 3 */
-       cfblk->lin_prio = 0;    /* Default priorities & backoff methods. */
-       cfblk->tbofstop = 0;
-       cfblk->exp_prio = 0;
-       cfblk->bof_met = 0;
-
-       /* Byte 4 */
-       cfblk->ifrm_spc = 6;    /* 96 bit times interframe spacing */
-
-       /* Byte 5 */
-       cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
-
-       /* Byte 6 */
-       cfblk->slottim_hi = 2;  /* 512 bit times slot time (high) */
-       cfblk->max_retr = 15;   /* 15 collisions retries */
-
-       /* Byte 7 */
-       cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
-       cfblk->bc_dis = 0;      /* Enable broadcast reception */
-       cfblk->crs_1 = 0;       /* Don't transmit without carrier sense */
-       cfblk->nocrc_ins = 0;   /* i82593 generates CRC */
-       cfblk->crc_1632 = 0;    /* 32-bit Autodin-II CRC */
-       cfblk->crs_cdt = 0;     /* CD not to be interpreted as CS */
-
-       /* Byte 8 */
-       cfblk->cs_filter = 0;   /* CS is recognized immediately */
-       cfblk->crs_src = 0;     /* External carrier sense */
-       cfblk->cd_filter = 0;   /* CD is recognized immediately */
-
-       /* Byte 9 */
-       cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
-
-       /* Byte A */
-       cfblk->lng_typ = 1;     /* Type/length checks OFF */
-       cfblk->lng_fld = 1;     /* Disable 802.3 length field check */
-       cfblk->rxcrc_xf = 1;    /* Don't transfer CRC to memory */
-       cfblk->artx = 1;        /* Disable automatic retransmission */
-       cfblk->sarec = 1;       /* Disable source addr trig of CD */
-       cfblk->tx_jabber = 0;   /* Disable jabber jam sequence */
-       cfblk->hash_1 = 1;      /* Use bits 0-5 in mc address hash */
-       cfblk->lbpkpol = 0;     /* Loopback pin active high */
-
-       /* Byte B */
-       cfblk->fdx = 0;         /* Disable full duplex operation */
-
-       /* Byte C */
-       cfblk->dummy_6 = 0x3f;  /* all ones, Default multicast addresses & backoff. */
-       cfblk->mult_ia = 0;     /* No multiple individual addresses */
-       cfblk->dis_bof = 0;     /* Disable the backoff algorithm ?! */
-
-       /* Byte D */
-       cfblk->dummy_1 = 1;     /* set to 1 */
-       cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
-       cfblk->mc_all = (!netdev_mc_empty(dev) ||
-                       (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
-       cfblk->rcv_mon = 0;     /* Monitor mode disabled */
-       cfblk->frag_acpt = 0;   /* Do not accept fragments */
-       cfblk->tstrttrs = 0;    /* No start transmission threshold */
-
-       /* Byte E */
-       cfblk->fretx = 1;       /* FIFO automatic retransmission */
-       cfblk->runt_eop = 0;    /* drop "runt" packets */
-       cfblk->hw_sw_pin = 0;   /* ?? */
-       cfblk->big_endn = 0;    /* Big Endian ? no... */
-       cfblk->syncrqs = 1;     /* Synchronous DRQ deassertion... */
-       cfblk->sttlen = 1;      /* 6 byte status registers */
-       cfblk->rx_eop = 0;      /* Signal EOP on packet reception */
-       cfblk->tx_eop = 0;      /* Signal EOP on packet transmission */
-
-       /* Byte F */
-       cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
-       cfblk->rcvstop = 1;     /* Enable Receive Stop Register */
-
-       if (znet_debug > 2) {
-               int i;
-               unsigned char *c;
-
-               for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
-                       printk ("%02X ", c[i]);
-               printk ("\n");
-       }
-
-       *znet->tx_cur++ = sizeof(struct i82593_conf_block);
-       memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
-       znet->tx_cur += sizeof(struct i82593_conf_block)/2;
-       outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
-       /* XXX FIXME maz : Add multicast addresses here, so having a
-        * multicast address configured isn't equal to IFF_ALLMULTI */
-}
-
-static const struct net_device_ops znet_netdev_ops = {
-       .ndo_open               = znet_open,
-       .ndo_stop               = znet_close,
-       .ndo_start_xmit         = znet_send_packet,
-       .ndo_set_rx_mode        = znet_set_multicast_list,
-       .ndo_tx_timeout         = znet_tx_timeout,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/* The Z-Note probe is pretty easy.  The NETIDBLK exists in the safe-to-probe
-   BIOS area.  We just scan for the signature, and pull the vital parameters
-   out of the structure. */
-
-static int __init znet_probe (void)
-{
-       int i;
-       struct netidblk *netinfo;
-       struct znet_private *znet;
-       struct net_device *dev;
-       char *p;
-       char *plast = phys_to_virt(0x100000 - NETIDBLK_MAGIC_SIZE);
-       int err = -ENOMEM;
-
-       /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
-       for(p = (char *)phys_to_virt(0xf0000); p <= plast; p++)
-               if (*p == 'N' &&
-                   strncmp(p, NETIDBLK_MAGIC, NETIDBLK_MAGIC_SIZE) == 0)
-                       break;
-
-       if (p > plast) {
-               if (znet_debug > 1)
-                       printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
-               return -ENODEV;
-       }
-
-       dev = alloc_etherdev(sizeof(struct znet_private));
-       if (!dev)
-               return -ENOMEM;
-
-       znet = netdev_priv(dev);
-
-       netinfo = (struct netidblk *)p;
-       dev->base_addr = netinfo->iobase1;
-       dev->irq = netinfo->irq1;
-
-       /* The station address is in the "netidblk" at 0x0f0000. */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = netinfo->netid[i];
-
-       printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
-              ", using IRQ %d DMA %d and %d.\n",
-              dev->name, dev->base_addr, dev->dev_addr,
-              dev->irq, netinfo->dma1, netinfo->dma2);
-
-       if (znet_debug > 1) {
-               printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
-                      dev->name, netinfo->vendor,
-                      netinfo->irq1, netinfo->irq2,
-                      netinfo->dma1, netinfo->dma2);
-               printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
-                      dev->name, netinfo->iobase1, netinfo->iosize1,
-                      netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
-       }
-
-       if (znet_debug > 0)
-               printk(KERN_INFO "%s", version);
-
-       znet->rx_dma = netinfo->dma1;
-       znet->tx_dma = netinfo->dma2;
-       spin_lock_init(&znet->lock);
-       znet->sia_base = 0xe6;  /* Magic address for the 82501 SIA */
-       znet->sia_size = 2;
-       /* maz: Despite the '593 being advertised above as using a
-        * single 8bits I/O port, this driver does many 16bits
-        * access. So set io_size accordingly */
-       znet->io_size  = 2;
-
-       if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
-               goto free_dev;
-       if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
-               goto free_rx;
-
-       if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
-           !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
-               printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
-               goto free_tx;
-       }
-
-       znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
-       znet->tx_buf_len = TX_BUF_SIZE/2;
-       znet->tx_end = znet->tx_start + znet->tx_buf_len;
-
-       /* The ZNET-specific entries in the device structure. */
-       dev->netdev_ops = &znet_netdev_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-       err = register_netdev(dev);
-       if (err)
-               goto free_tx;
-       znet_dev = dev;
-       return 0;
-
- free_tx:
-       kfree(znet->tx_start);
- free_rx:
-       kfree(znet->rx_start);
- free_dev:
-       free_netdev(dev);
-       return err;
-}
-
-
-static int znet_open(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       if (znet_debug > 2)
-               printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
-
-       /* These should never fail.  You can't add devices to a sealed box! */
-       if (znet_request_resources (dev)) {
-               printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
-               return -EBUSY;
-       }
-
-       znet_transceiver_power (dev, 1);
-
-       /* According to the Crynwr driver we should wait 50 msec. for the
-          LAN clock to stabilize.  My experiments indicates that the '593 can
-          be initialized immediately.  The delay is probably needed for the
-          DC-to-DC converter to come up to full voltage, and for the oscillator
-          to be spot-on at 20Mhz before transmitting.
-          Until this proves to be a problem we rely on the higher layers for the
-          delay and save allocating a timer entry. */
-
-       /* maz : Well, I'm getting every time the following message
-        * without the delay on a 486@33. This machine is much too
-        * fast... :-) So maybe the Crynwr driver wasn't wrong after
-        * all, even if the message is completly harmless on my
-        * setup. */
-       mdelay (50);
-
-       /* This follows the packet driver's lead, and checks for success. */
-       if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
-               printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
-                      dev->name);
-
-       hardware_init(dev);
-       netif_start_queue (dev);
-
-       return 0;
-}
-
-
-static void znet_tx_timeout (struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       ushort event, tx_status, rx_offset, state;
-
-       outb (CR0_STATUS_0, ioaddr);
-       event = inb (ioaddr);
-       outb (CR0_STATUS_1, ioaddr);
-       tx_status = inw (ioaddr);
-       outb (CR0_STATUS_2, ioaddr);
-       rx_offset = inw (ioaddr);
-       outb (CR0_STATUS_3, ioaddr);
-       state = inb (ioaddr);
-       printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
-        " resetting.\n", dev->name, event, tx_status, rx_offset, state);
-       if (tx_status == TX_LOST_CRS)
-               printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
-                       dev->name);
-       outb (OP0_RESET, ioaddr);
-       hardware_init (dev);
-       netif_wake_queue (dev);
-}
-
-static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct znet_private *znet = netdev_priv(dev);
-       unsigned long flags;
-       short length = skb->len;
-
-       if (znet_debug > 4)
-               printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-
-       netif_stop_queue (dev);
-
-       /* Check that the part hasn't reset itself, probably from suspend. */
-       outb(CR0_STATUS_0, ioaddr);
-       if (inw(ioaddr) == 0x0010 &&
-           inw(ioaddr) == 0x0000 &&
-           inw(ioaddr) == 0x0010) {
-               if (znet_debug > 1)
-                       printk (KERN_WARNING "%s : waking up\n", dev->name);
-               hardware_init(dev);
-               znet_transceiver_power (dev, 1);
-       }
-
-       if (1) {
-               unsigned char *buf = (void *)skb->data;
-               ushort *tx_link = znet->tx_cur - 1;
-               ushort rnd_len = (length + 1)>>1;
-
-               dev->stats.tx_bytes+=length;
-
-               if (znet->tx_cur >= znet->tx_end)
-                 znet->tx_cur = znet->tx_start;
-               *znet->tx_cur++ = length;
-               if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
-                       int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
-                       memcpy(znet->tx_cur, buf, semi_cnt);
-                       rnd_len -= semi_cnt>>1;
-                       memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
-                       znet->tx_cur = znet->tx_start + rnd_len;
-               } else {
-                       memcpy(znet->tx_cur, buf, skb->len);
-                       znet->tx_cur += rnd_len;
-               }
-               *znet->tx_cur++ = 0;
-
-               spin_lock_irqsave(&znet->lock, flags);
-               {
-                       *tx_link = OP0_TRANSMIT | CR0_CHNL;
-                       /* Is this always safe to do? */
-                       outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
-               }
-               spin_unlock_irqrestore (&znet->lock, flags);
-
-               netif_start_queue (dev);
-
-               if (znet_debug > 4)
-                 printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
-       }
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-/* The ZNET interrupt handler. */
-static irqreturn_t znet_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct znet_private *znet = netdev_priv(dev);
-       int ioaddr;
-       int boguscnt = 20;
-       int handled = 0;
-
-       spin_lock (&znet->lock);
-
-       ioaddr = dev->base_addr;
-
-       outb(CR0_STATUS_0, ioaddr);
-       do {
-               ushort status = inb(ioaddr);
-               if (znet_debug > 5) {
-                       ushort result, rx_ptr, running;
-                       outb(CR0_STATUS_1, ioaddr);
-                       result = inw(ioaddr);
-                       outb(CR0_STATUS_2, ioaddr);
-                       rx_ptr = inw(ioaddr);
-                       outb(CR0_STATUS_3, ioaddr);
-                       running = inb(ioaddr);
-                       printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
-                                dev->name, status, result, rx_ptr, running, boguscnt);
-               }
-               if ((status & SR0_INTERRUPT) == 0)
-                       break;
-
-               handled = 1;
-
-               if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
-                   (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
-                   (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
-                       int tx_status;
-                       outb(CR0_STATUS_1, ioaddr);
-                       tx_status = inw(ioaddr);
-                       /* It's undocumented, but tx_status seems to match the i82586. */
-                       if (tx_status & TX_OK) {
-                               dev->stats.tx_packets++;
-                               dev->stats.collisions += tx_status & TX_NCOL_MASK;
-                       } else {
-                               if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
-                                       dev->stats.tx_carrier_errors++;
-                               if (tx_status & TX_UND_RUN)
-                                       dev->stats.tx_fifo_errors++;
-                               if (!(tx_status & TX_HRT_BEAT))
-                                       dev->stats.tx_heartbeat_errors++;
-                               if (tx_status & TX_MAX_COL)
-                                       dev->stats.tx_aborted_errors++;
-                               /* ...and the catch-all. */
-                               if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
-                                       dev->stats.tx_errors++;
-
-                               /* Transceiver may be stuck if cable
-                                * was removed while emitting a
-                                * packet. Flip it off, then on to
-                                * reset it. This is very empirical,
-                                * but it seems to work. */
-
-                               znet_transceiver_power (dev, 0);
-                               znet_transceiver_power (dev, 1);
-                       }
-                       netif_wake_queue (dev);
-               }
-
-               if ((status & SR0_RECEPTION) ||
-                   (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
-                       znet_rx(dev);
-               }
-               /* Clear the interrupts we've handled. */
-               outb(CR0_INT_ACK, ioaddr);
-       } while (boguscnt--);
-
-       spin_unlock (&znet->lock);
-
-       return IRQ_RETVAL(handled);
-}
-
-static void znet_rx(struct net_device *dev)
-{
-       struct znet_private *znet = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int boguscount = 1;
-       short next_frame_end_offset = 0;                /* Offset of next frame start. */
-       short *cur_frame_end;
-       short cur_frame_end_offset;
-
-       outb(CR0_STATUS_2, ioaddr);
-       cur_frame_end_offset = inw(ioaddr);
-
-       if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
-               printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
-                          dev->name, cur_frame_end_offset);
-               return;
-       }
-
-       /* Use same method as the Crynwr driver: construct a forward list in
-          the same area of the backwards links we now have.  This allows us to
-          pass packets to the upper layers in the order they were received --
-          important for fast-path sequential operations. */
-       while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
-              ++boguscount < 5) {
-               unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
-               int count, status;
-
-               if (cur_frame_end_offset < 4) {
-                       /* Oh no, we have a special case: the frame trailer wraps around
-                          the end of the ring buffer.  We've saved space at the end of
-                          the ring buffer for just this problem. */
-                       memcpy(znet->rx_end, znet->rx_start, 8);
-                       cur_frame_end_offset += (RX_BUF_SIZE/2);
-               }
-               cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
-
-               lo_status = *cur_frame_end++;
-               hi_status = *cur_frame_end++;
-               status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
-               lo_cnt = *cur_frame_end++;
-               hi_cnt = *cur_frame_end++;
-               count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
-
-               if (znet_debug > 5)
-                 printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
-                                " count %#x status %04x.\n",
-                                cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
-                                count, status);
-               cur_frame_end[-4] = status;
-               cur_frame_end[-3] = next_frame_end_offset;
-               cur_frame_end[-2] = count;
-               next_frame_end_offset = cur_frame_end_offset;
-               cur_frame_end_offset -= ((count + 1)>>1) + 3;
-               if (cur_frame_end_offset < 0)
-                 cur_frame_end_offset += RX_BUF_SIZE/2;
-       }
-
-       /* Now step  forward through the list. */
-       do {
-               ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
-               int status = this_rfp_ptr[-4];
-               int pkt_len = this_rfp_ptr[-2];
-
-               if (znet_debug > 5)
-                 printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
-                                " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
-                                this_rfp_ptr[-3]<<1);
-               /* Once again we must assume that the i82586 docs apply. */
-               if ( ! (status & RX_RCV_OK)) { /* There was an error. */
-                       dev->stats.rx_errors++;
-                       if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
-                       if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
-#if 0
-                       if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
-                       if (status & 0x0100) dev->stats.rx_fifo_errors++;
-#else
-                       /* maz : Wild guess... */
-                       if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
-#endif
-                       if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
-               } else if (pkt_len > 1536) {
-                       dev->stats.rx_length_errors++;
-               } else {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       skb = netdev_alloc_skb(dev, pkt_len);
-                       if (skb == NULL) {
-                               if (znet_debug)
-                                 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-                               dev->stats.rx_dropped++;
-                               break;
-                       }
-
-                       if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
-                               int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
-                               memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
-                               memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
-                                          pkt_len - semi_cnt);
-                       } else {
-                               memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
-                               if (znet_debug > 6) {
-                                       unsigned int *packet = (unsigned int *) skb->data;
-                                       printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
-                                                  packet[1], packet[2], packet[3]);
-                               }
-                 }
-                 skb->protocol=eth_type_trans(skb,dev);
-                 netif_rx(skb);
-                 dev->stats.rx_packets++;
-                 dev->stats.rx_bytes += pkt_len;
-               }
-               znet->rx_cur = this_rfp_ptr;
-               if (znet->rx_cur >= znet->rx_end)
-                       znet->rx_cur -= RX_BUF_SIZE/2;
-               update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
-               next_frame_end_offset = this_rfp_ptr[-3];
-               if (next_frame_end_offset == 0)         /* Read all the frames? */
-                       break;                  /* Done for now */
-               this_rfp_ptr = znet->rx_start + next_frame_end_offset;
-       } while (--boguscount);
-
-       /* If any worth-while packets have been received, dev_rint()
-          has done a mark_bh(INET_BH) for us and will work on them
-          when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to znet_open(). */
-static int znet_close(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       netif_stop_queue (dev);
-
-       outb(OP0_RESET, ioaddr);                        /* CMD0_RESET */
-
-       if (znet_debug > 1)
-               printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
-       /* Turn off transceiver power. */
-       znet_transceiver_power (dev, 0);
-
-       znet_release_resources (dev);
-
-       return 0;
-}
-
-static void show_dma(struct net_device *dev)
-{
-       short ioaddr = dev->base_addr;
-       unsigned char stat = inb (ioaddr);
-       struct znet_private *znet = netdev_priv(dev);
-       unsigned long flags;
-       short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
-       unsigned addr = inb(dma_port);
-       short residue;
-
-       addr |= inb(dma_port) << 8;
-       residue = get_dma_residue(znet->tx_dma);
-
-       if (znet_debug > 1) {
-               flags=claim_dma_lock();
-               printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
-                      stat, addr<<1, residue);
-               release_dma_lock(flags);
-       }
-}
-
-/* Initialize the hardware.  We have to do this when the board is open()ed
-   or when we come out of suspend mode. */
-static void hardware_init(struct net_device *dev)
-{
-       unsigned long flags;
-       short ioaddr = dev->base_addr;
-       struct znet_private *znet = netdev_priv(dev);
-
-       znet->rx_cur = znet->rx_start;
-       znet->tx_cur = znet->tx_start;
-
-       /* Reset the chip, and start it up. */
-       outb(OP0_RESET, ioaddr);
-
-       flags=claim_dma_lock();
-       disable_dma(znet->rx_dma);              /* reset by an interrupting task. */
-       clear_dma_ff(znet->rx_dma);
-       set_dma_mode(znet->rx_dma, DMA_RX_MODE);
-       set_dma_addr(znet->rx_dma, isa_virt_to_bus(znet->rx_start));
-       set_dma_count(znet->rx_dma, RX_BUF_SIZE);
-       enable_dma(znet->rx_dma);
-       /* Now set up the Tx channel. */
-       disable_dma(znet->tx_dma);
-       clear_dma_ff(znet->tx_dma);
-       set_dma_mode(znet->tx_dma, DMA_TX_MODE);
-       set_dma_addr(znet->tx_dma, isa_virt_to_bus(znet->tx_start));
-       set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
-       enable_dma(znet->tx_dma);
-       release_dma_lock(flags);
-
-       if (znet_debug > 1)
-         printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
-                        dev->name, znet->rx_start,znet->tx_start);
-       /* Do an empty configure command, just like the Crynwr driver.  This
-          resets to chip to its default values. */
-       *znet->tx_cur++ = 0;
-       *znet->tx_cur++ = 0;
-       show_dma(dev);
-       outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
-       znet_set_multicast_list (dev);
-
-       *znet->tx_cur++ = 6;
-       memcpy(znet->tx_cur, dev->dev_addr, 6);
-       znet->tx_cur += 3;
-       show_dma(dev);
-       outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
-       show_dma(dev);
-
-       update_stop_hit(ioaddr, 8192);
-       if (znet_debug > 1)  printk(KERN_DEBUG "enabling Rx.\n");
-       outb(OP0_RCV_ENABLE, ioaddr);
-       netif_start_queue (dev);
-}
-
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
-{
-       outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
-       if (znet_debug > 5)
-         printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
-                        (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
-       outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
-       outb(OP1_SWIT_TO_PORT_0, ioaddr);
-}
-
-static __exit void znet_cleanup (void)
-{
-       if (znet_dev) {
-               struct znet_private *znet = netdev_priv(znet_dev);
-
-               unregister_netdev (znet_dev);
-               kfree (znet->rx_start);
-               kfree (znet->tx_start);
-               free_netdev (znet_dev);
-       }
-}
-
-module_init (znet_probe);
-module_exit (znet_cleanup);
index 256bdb8e19948390eeb4e73513b475e377350849..4989481c19f01b6dad9b560b535b6127da416eee 100644 (file)
@@ -2190,11 +2190,10 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
 {
        struct emac_instance *dev = netdev_priv(ndev);
 
-       strcpy(info->driver, "ibm_emac");
-       strcpy(info->version, DRV_VERSION);
-       info->fw_version[0] = '\0';
-       sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
-               dev->cell_index, dev->ofdev->dev.of_node->full_name);
+       strlcpy(info->driver, "ibm_emac", sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s",
+                dev->cell_index, dev->ofdev->dev.of_node->full_name);
        info->regdump_len = emac_ethtool_get_regs_len(ndev);
 }
 
index f2fdbb79837eafcc7baf00d070efb48251bd1f7a..4181f6e99c0003ba6f2ed1ae2055e0365dbd8e29 100644 (file)
@@ -722,9 +722,8 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, ibmveth_driver_name, sizeof(info->driver) - 1);
-       strncpy(info->version, ibmveth_driver_version,
-               sizeof(info->version) - 1);
+       strlcpy(info->driver, ibmveth_driver_name, sizeof(info->driver));
+       strlcpy(info->version, ibmveth_driver_version, sizeof(info->version));
 }
 
 static netdev_features_t ibmveth_fix_features(struct net_device *dev,
index ddee4060948a3688d884b3591bdc7aee4d992992..3d5f6d463757ff06d95a88d6fe13b22ec2ff7788 100644 (file)
@@ -6,7 +6,7 @@ config NET_VENDOR_INTEL
        bool "Intel devices"
        default y
        depends on PCI || PCI_MSI || ISA || ISA_DMA_API || ARM || \
-                  ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
+                  ARCH_ACORN || SNI_RM || SUN3 || \
                   GSC || BVME6000 || MVME16x || \
                   (ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR) || \
                   EXPERIMENTAL
@@ -74,6 +74,7 @@ config E1000E
        tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
        depends on PCI && (!SPARC32 || BROKEN)
        select CRC32
+       select PTP_1588_CLOCK
        ---help---
          This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
          ethernet family of adapters. For PCI or PCI-X e1000 adapters,
@@ -94,6 +95,8 @@ config IGB
        tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
        depends on PCI
        select PTP_1588_CLOCK
+       select I2C
+       select I2C_ALGOBIT
        ---help---
          This driver supports Intel(R) 82575/82576 gigabit ethernet family of
          adapters.  For more information on how to identify your adapter, go
@@ -112,6 +115,17 @@ config IGB
          To compile this driver as a module, choose M here. The module
          will be called igb.
 
+config IGB_HWMON
+       bool "Intel(R) PCI-Express Gigabit adapters HWMON support"
+       default y
+       depends on IGB && HWMON && !(IGB=y && HWMON=m)
+       ---help---
+         Say Y if you want to expose thermal sensor data on Intel devices.
+
+         Some of our devices contain thermal sensors, both external and internal.
+         This data is available via the hwmon sysfs interface and exposes
+         the onboard sensors.
+
 config IGB_DCA
        bool "Direct Cache Access (DCA) Support"
        default y
index a59f0779e1c3a00a2603c54eb21343cd962945b5..ec800b093e7eb22536b7247289d13c0450b9552f 100644 (file)
@@ -2928,8 +2928,7 @@ static int e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        e100_phy_init(nic);
 
        memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
-       memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
-       if (!is_valid_ether_addr(netdev->perm_addr)) {
+       if (!is_valid_ether_addr(netdev->dev_addr)) {
                if (!eeprom_bad_csum_allow) {
                        netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, aborting\n");
                        err = -EAGAIN;
index 294da56b824c3d0c4259b76f01858c80914fccbf..b20fff134378497785ece66e6f08fc226413e2f7 100644 (file)
@@ -1123,9 +1123,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        /* don't block initalization here due to bad MAC address */
        memcpy(netdev->dev_addr, hw->mac_addr, netdev->addr_len);
-       memcpy(netdev->perm_addr, hw->mac_addr, netdev->addr_len);
 
-       if (!is_valid_ether_addr(netdev->perm_addr))
+       if (!is_valid_ether_addr(netdev->dev_addr))
                e_err(probe, "Invalid MAC Address\n");
 
 
index e73c2c35599375a45bc253783df6cdfd2b91385d..3f27546baaa7fdfa0a776ddfad537ba943d82d32 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -111,11 +111,10 @@ static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
-static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
-static s32  e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                            u16 *data);
-static s32  e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                             u16 data);
+static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                          u16 *data);
+static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                           u16 data);
 static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
 
 /**
@@ -696,7 +695,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
 static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
 {
        struct e1000_phy_info *phy = &hw->phy;
-       s32 ret_val = 0;
+       s32 ret_val;
        u16 phy_data, index;
 
        ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
@@ -774,6 +773,9 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
        ctrl = er32(CTRL);
 
        ret_val = e1000_acquire_phy_80003es2lan(hw);
+       if (ret_val)
+               return ret_val;
+
        e_dbg("Issuing a global reset to MAC\n");
        ew32(CTRL, ctrl | E1000_CTRL_RST);
        e1000_release_phy_80003es2lan(hw);
@@ -833,6 +835,8 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
 
        /* Setup link and flow control */
        ret_val = mac->ops.setup_link(hw);
+       if (ret_val)
+               return ret_val;
 
        /* Disable IBIST slave mode (far-end loopback) */
        e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
@@ -1006,7 +1010,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
                return ret_val;
 
        /* SW Reset the PHY so all changes take effect */
-       ret_val = e1000e_commit_phy(hw);
+       ret_val = hw->phy.ops.commit(hw);
        if (ret_val) {
                e_dbg("Error Resetting the PHY\n");
                return ret_val;
@@ -1272,7 +1276,7 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
                                           u16 *data)
 {
        u32 kmrnctrlsta;
-       s32 ret_val = 0;
+       s32 ret_val;
 
        ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
        if (ret_val)
@@ -1307,7 +1311,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
                                            u16 data)
 {
        u32 kmrnctrlsta;
-       s32 ret_val = 0;
+       s32 ret_val;
 
        ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
        if (ret_val)
@@ -1331,7 +1335,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
  **/
 static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
 {
-       s32 ret_val = 0;
+       s32 ret_val;
 
        /* If there's an alternate MAC address place it in RAR0
         * so that it will override the Si installed default perm
index c77d010d5c5992da6c25761f6d1e1747f12d3273..076938c87a26030cdc2601866516892d4be749c1 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -67,9 +67,7 @@ static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
                                      u16 words, u16 *data);
 static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
-static s32 e1000_setup_link_82571(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
-static void e1000_clear_vfta_82571(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
 static s32 e1000_led_on_82574(struct e1000_hw *hw);
 static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
@@ -556,16 +554,14 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
        s32 i = 0;
 
        extcnf_ctrl = er32(EXTCNF_CTRL);
-       extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
        do {
+               extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
                ew32(EXTCNF_CTRL, extcnf_ctrl);
                extcnf_ctrl = er32(EXTCNF_CTRL);
 
                if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
                        break;
 
-               extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
                usleep_range(2000, 4000);
                i++;
        } while (i < MDIO_OWNERSHIP_TIMEOUT);
@@ -937,6 +933,8 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
 
                /* When LPLU is enabled, we should disable SmartSpeed */
                ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+               if (ret_val)
+                       return ret_val;
                data &= ~IGP01E1000_PSCFR_SMART_SPEED;
                ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
                if (ret_val)
@@ -1399,7 +1397,7 @@ bool e1000_check_phy_82574(struct e1000_hw *hw)
 {
        u16 status_1kbt = 0;
        u16 receive_errors = 0;
-       s32 ret_val = 0;
+       s32 ret_val;
 
        /* Read PHY Receive Error counter first, if its is max - all F's then
         * read the Base1000T status register If both are max then PHY is hung.
@@ -1544,7 +1542,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
 
        ctrl = er32(CTRL);
        status = er32(STATUS);
-       rxcw = er32(RXCW);
+       er32(RXCW);
        /* SYNCH bit and IV bit are sticky */
        udelay(10);
        rxcw = er32(RXCW);
@@ -1799,6 +1797,8 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
                        if (ret_val)
                                return ret_val;
                        ret_val = e1000e_update_nvm_checksum(hw);
+                       if (ret_val)
+                               return ret_val;
                }
        }
 
@@ -1812,7 +1812,7 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
 static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
 {
        if (hw->mac.type == e1000_82571) {
-               s32 ret_val = 0;
+               s32 ret_val;
 
                /* If there's an alternate MAC address place it in RAR0
                 * so that it will override the Si installed default perm
@@ -1940,7 +1940,7 @@ static const struct e1000_phy_operations e82_phy_ops_m88 = {
        .check_reset_block      = e1000e_check_reset_block_generic,
        .commit                 = e1000e_phy_sw_reset,
        .force_speed_duplex     = e1000e_phy_force_speed_duplex_m88,
-       .get_cfg_done           = e1000e_get_cfg_done,
+       .get_cfg_done           = e1000e_get_cfg_done_generic,
        .get_cable_length       = e1000e_get_cable_length_m88,
        .get_info               = e1000e_get_phy_info_m88,
        .read_reg               = e1000e_read_phy_reg_m88,
@@ -1958,7 +1958,7 @@ static const struct e1000_phy_operations e82_phy_ops_bm = {
        .check_reset_block      = e1000e_check_reset_block_generic,
        .commit                 = e1000e_phy_sw_reset,
        .force_speed_duplex     = e1000e_phy_force_speed_duplex_m88,
-       .get_cfg_done           = e1000e_get_cfg_done,
+       .get_cfg_done           = e1000e_get_cfg_done_generic,
        .get_cable_length       = e1000e_get_cable_length_m88,
        .get_info               = e1000e_get_phy_info_m88,
        .read_reg               = e1000e_read_phy_reg_bm2,
@@ -2044,6 +2044,7 @@ const struct e1000_info e1000_82574_info = {
                                  | FLAG_HAS_MSIX
                                  | FLAG_HAS_JUMBO_FRAMES
                                  | FLAG_HAS_WOL
+                                 | FLAG_HAS_HW_TIMESTAMP
                                  | FLAG_APME_IN_CTRL3
                                  | FLAG_HAS_SMART_POWER_DOWN
                                  | FLAG_HAS_AMT
@@ -2065,6 +2066,7 @@ const struct e1000_info e1000_82583_info = {
        .mac                    = e1000_82583,
        .flags                  = FLAG_HAS_HW_VLAN_FILTER
                                  | FLAG_HAS_WOL
+                                 | FLAG_HAS_HW_TIMESTAMP
                                  | FLAG_APME_IN_CTRL3
                                  | FLAG_HAS_SMART_POWER_DOWN
                                  | FLAG_HAS_AMT
index 591b713245057fc4b2ae2fccf797665090ef972c..c2dcfcc10857fc17608194c0a4c09140f6606143 100644 (file)
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
@@ -34,5 +34,5 @@ obj-$(CONFIG_E1000E) += e1000e.o
 
 e1000e-objs := 82571.o ich8lan.o 80003es2lan.o \
               mac.o manage.o nvm.o phy.o \
-              param.o ethtool.o netdev.o
+              param.o ethtool.o netdev.o ptp.o
 
index 02a12b69555f6fb5d71fe2089992f5fad5e354cc..d29b2fd4c09c8d685b120a73994ffd078aadc377 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
 #define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
 
+#define E1000_RXDEXT_STATERR_TST   0x00000100  /* Time Stamp taken */
 #define E1000_RXDEXT_STATERR_CE    0x01000000
 #define E1000_RXDEXT_STATERR_SE    0x02000000
 #define E1000_RXDEXT_STATERR_SEQ   0x04000000
 #define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
 #define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */
 #define E1000_CTRL_LANPHYPC_VALUE    0x00020000 /* SW value of LANPHYPC */
+#define E1000_CTRL_MEHE     0x00080000  /* Memory Error Handling Enable */
 #define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
 #define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
 #define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
 #define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
 #define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
 
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
+#define E1000_PCS_LCTL_FORCE_FCTRL     0x80
+
+#define E1000_PCS_LSTS_AN_COMPLETE     0x10000
 
 /* Device Status */
 #define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
 #define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
 #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
 
-/* Constants used to interpret the masked PCI-X bus speed. */
-
 #define HALF_DUPLEX 1
 #define FULL_DUPLEX 2
 
 #define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
 #define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
 #define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+#define E1000_TXD_EXTCMD_TSTAMP        0x00000010 /* IEEE1588 Timestamp packet */
 
 /* Transmit Control */
 #define E1000_TCTL_EN     0x00000002    /* enable Tx */
 #define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
 #define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
 
-/* Transmit Arbitration Count */
-
 /* SerDes Control */
 #define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
 
 
 #define E1000_KABGTXD_BGSQLBIAS           0x00050000
 
+/* Low Power IDLE Control */
+#define E1000_LPIC_LPIET_SHIFT         24      /* Low Power Idle Entry Time */
+
 /* PBA constants */
 #define E1000_PBA_8K  0x0008    /* 8KB */
 #define E1000_PBA_16K 0x0010    /* 16KB */
 
+#define E1000_PBA_RXA_MASK     0xFFFF
+
 #define E1000_PBS_16K E1000_PBA_16K
 
+/* Uncorrectable/correctable ECC Error counts and enable bits */
+#define E1000_PBECCSTS_CORR_ERR_CNT_MASK       0x000000FF
+#define E1000_PBECCSTS_UNCORR_ERR_CNT_MASK     0x0000FF00
+#define E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT    8
+#define E1000_PBECCSTS_ECC_ENABLE              0x00010000
+
 #define IFS_MAX       80
 #define IFS_MIN       40
 #define IFS_RATIO     4
 #define E1000_ICR_RXSEQ         0x00000008 /* Rx sequence error */
 #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
 #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
+#define E1000_ICR_ECCER         0x00400000 /* Uncorrectable ECC Error */
 #define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
 #define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
 #define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
 #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
 #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
 #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* Rx timer intr */
+#define E1000_IMS_ECCER     E1000_ICR_ECCER     /* Uncorrectable ECC Error */
 #define E1000_IMS_RXQ0      E1000_ICR_RXQ0      /* Rx Queue 0 Interrupt */
 #define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
 #define E1000_IMS_TXQ0      E1000_ICR_TXQ0      /* Tx Queue 0 Interrupt */
 #define E1000_RXCW_C          0x20000000        /* Receive config */
 #define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
 
+#define E1000_TSYNCTXCTL_VALID         0x00000001 /* Tx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_ALL      0x08
+#define E1000_TSYNCTXCTL_ENABLED       0x00000010 /* enable Tx timestamping */
+
+#define E1000_TSYNCRXCTL_VALID         0x00000001 /* Rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK     0x0000000E /* Rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2    0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1    0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL      0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
+#define E1000_TSYNCRXCTL_ENABLED       0x00000010 /* enable Rx timestamping */
+#define E1000_TSYNCRXCTL_SYSCFI                0x00000020 /* Sys clock frequency */
+
+#define E1000_RXMTRL_PTP_V1_SYNC_MESSAGE       0x00000000
+#define E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE  0x00010000
+
+#define E1000_RXMTRL_PTP_V2_SYNC_MESSAGE       0x00000000
+#define E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE  0x01000000
+
+#define E1000_TIMINCA_INCPERIOD_SHIFT  24
+#define E1000_TIMINCA_INCVALUE_MASK    0x00FFFFFF
+
 /* PCI Express Control */
 #define E1000_GCR_RXD_NO_SNOOP          0x00000001
 #define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
 /* NVM Word Offsets */
 #define NVM_COMPAT                 0x0003
 #define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_FUTURE_INIT_WORD1      0x0019
+#define NVM_COMPAT_VALID_CSUM      0x0001
+#define NVM_FUTURE_INIT_WORD1_VALID_CSUM       0x0040
+
 #define NVM_INIT_CONTROL2_REG      0x000F
 #define NVM_INIT_CONTROL3_PORT_B   0x0014
 #define NVM_INIT_3GIO_3            0x001A
 #define M88E1000_PSCR_AUTO_X_1000T     0x0040
 /* Auto crossover enabled all speeds */
 #define M88E1000_PSCR_AUTO_X_MODE      0x0060
-/* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold)
- * 0=Normal 10BASE-T Rx Threshold
- */
 #define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
 
 /* M88E1000 PHY Specific Status Register */
 /* BME1000 PHY Specific Control Register */
 #define BME1000_PSCR_ENABLE_DOWNSHIFT   0x0800 /* 1 = enable downshift */
 
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL                                PHY_REG(772, 20)
+#define I82579_LPI_CTRL_100_ENABLE             0x2000
+#define I82579_LPI_CTRL_1000_ENABLE            0x4000
+#define I82579_LPI_CTRL_ENABLE_MASK            0x6000
+#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT   0x80
+
+/* Extended Management Interface (EMI) Registers */
+#define I82579_EMI_ADDR                0x10
+#define I82579_EMI_DATA                0x11
+#define I82579_LPI_UPDATE_TIMER        0x4805  /* in 40ns units + 40 ns base value */
+#define I82579_MSE_THRESHOLD   0x084F  /* 82579 Mean Square Error Threshold */
+#define I82577_MSE_THRESHOLD   0x0887  /* 82577 Mean Square Error Threshold */
+#define I82579_MSE_LINK_DOWN   0x2411  /* MSE count before dropping link */
+#define I82579_EEE_PCS_STATUS  0x182D  /* IEEE MMD Register 3.1 >> 8 */
+#define I82579_EEE_CAPABILITY  0x0410  /* IEEE MMD Register 3.20 */
+#define I82579_EEE_ADVERTISEMENT       0x040E  /* IEEE MMD Register 7.60 */
+#define I82579_EEE_LP_ABILITY          0x040F  /* IEEE MMD Register 7.61 */
+#define I82579_EEE_100_SUPPORTED       (1 << 1) /* 100BaseTx EEE supported */
+#define I82579_EEE_1000_SUPPORTED      (1 << 2) /* 1000BaseTx EEE supported */
+#define I217_EEE_PCS_STATUS    0x9401  /* IEEE MMD Register 3.1 */
+#define I217_EEE_CAPABILITY    0x8000  /* IEEE MMD Register 3.20 */
+#define I217_EEE_ADVERTISEMENT 0x8001  /* IEEE MMD Register 7.60 */
+#define I217_EEE_LP_ABILITY    0x8002  /* IEEE MMD Register 7.61 */
+
+#define E1000_EEE_RX_LPI_RCVD  0x0400  /* Tx LP idle received */
+#define E1000_EEE_TX_LPI_RCVD  0x0800  /* Rx LP idle received */
 
 #define PHY_PAGE_SHIFT 5
 #define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
index 6782a2eea1bcbfb893681b8d26428d8b0410981b..c7d5c5b92ee51ebece454d5b974e54800157d374 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #include <linux/pci-aspm.h>
 #include <linux/crc32.h>
 #include <linux/if_vlan.h>
-
+#include <linux/clocksource.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ptp_classify.h>
 #include "hw.h"
 
 struct e1000_info;
@@ -75,9 +78,6 @@ struct e1000_info;
 #define E1000_MIN_ITR_USECS            10 /* 100000 irq/sec */
 #define E1000_MAX_ITR_USECS            10000 /* 100    irq/sec */
 
-/* Early Receive defines */
-#define E1000_ERT_2048                 0x100
-
 #define E1000_FC_PAUSE_TIME            0x0680 /* 858 usec */
 
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
@@ -309,6 +309,8 @@ struct e1000_adapter {
 
        struct napi_struct napi;
 
+       unsigned int uncorr_errors;     /* uncorrectable ECC errors */
+       unsigned int corr_errors;       /* correctable ECC errors */
        unsigned int restart_queue;
        u32 txd_cmd;
 
@@ -353,6 +355,7 @@ struct e1000_adapter {
        u64 gorc_old;
        u32 alloc_rx_buff_failed;
        u32 rx_dma_failed;
+       u32 rx_hwtstamp_cleared;
 
        unsigned int rx_ps_pages;
        u16 rx_ps_bsize0;
@@ -366,7 +369,7 @@ struct e1000_adapter {
        /* structs defined in e1000_hw.h */
        struct e1000_hw hw;
 
-       spinlock_t stats64_lock;
+       spinlock_t stats64_lock;        /* protects statistics counters */
        struct e1000_hw_stats stats;
        struct e1000_phy_info phy_info;
        struct e1000_phy_stats phy_stats;
@@ -402,6 +405,16 @@ struct e1000_adapter {
 
        u16 tx_ring_count;
        u16 rx_ring_count;
+
+       struct hwtstamp_config hwtstamp_config;
+       struct delayed_work systim_overflow_work;
+       struct sk_buff *tx_hwtstamp_skb;
+       struct work_struct tx_hwtstamp_work;
+       spinlock_t systim_lock; /* protects SYSTIML/H regsters */
+       struct cyclecounter cc;
+       struct timecounter tc;
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info ptp_clock_info;
 };
 
 struct e1000_info {
@@ -416,6 +429,40 @@ struct e1000_info {
        const struct e1000_nvm_operations *nvm_ops;
 };
 
+s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
+
+/* The system time is maintained by a 64-bit counter comprised of the 32-bit
+ * SYSTIMH and SYSTIML registers.  How the counter increments (and therefore
+ * its resolution) is based on the contents of the TIMINCA register - it
+ * increments every incperiod (bits 31:24) clock ticks by incvalue (bits 23:0).
+ * For the best accuracy, the incperiod should be as small as possible.  The
+ * incvalue is scaled by a factor as large as possible (while still fitting
+ * in bits 23:0) so that relatively small clock corrections can be made.
+ *
+ * As a result, a shift of INCVALUE_SHIFT_n is used to fit a value of
+ * INCVALUE_n into the TIMINCA register allowing 32+8+(24-INCVALUE_SHIFT_n)
+ * bits to count nanoseconds leaving the rest for fractional nonseconds.
+ */
+#define INCVALUE_96MHz         125
+#define INCVALUE_SHIFT_96MHz   17
+#define INCPERIOD_SHIFT_96MHz  2
+#define INCPERIOD_96MHz                (12 >> INCPERIOD_SHIFT_96MHz)
+
+#define INCVALUE_25MHz         40
+#define INCVALUE_SHIFT_25MHz   18
+#define INCPERIOD_25MHz                1
+
+/* Another drawback of scaling the incvalue by a large factor is the
+ * 64-bit SYSTIM register overflows more quickly.  This is dealt with
+ * by simply reading the clock before it overflows.
+ *
+ * Clock       ns bits Overflows after
+ * ~~~~~~      ~~~~~~~ ~~~~~~~~~~~~~~~
+ * 96MHz       47-bit  2^(47-INCPERIOD_SHIFT_96MHz) / 10^9 / 3600 = 9.77 hrs
+ * 25MHz       46-bit  2^46 / 10^9 / 3600 = 19.55 hours
+ */
+#define E1000_SYSTIM_OVERFLOW_PERIOD   (HZ * 60 * 60 * 4)
+
 /* hardware capability, feature, and workaround flags */
 #define FLAG_HAS_AMT                      (1 << 0)
 #define FLAG_HAS_FLASH                    (1 << 1)
@@ -431,7 +478,7 @@ struct e1000_info {
 #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
 #define FLAG_IS_QUAD_PORT_A               (1 << 12)
 #define FLAG_IS_QUAD_PORT                 (1 << 13)
-/* reserved bit14 */
+#define FLAG_HAS_HW_TIMESTAMP             (1 << 14)
 #define FLAG_APME_IN_WUC                  (1 << 15)
 #define FLAG_APME_IN_CTRL3                (1 << 16)
 #define FLAG_APME_CHECK_PORT_B            (1 << 17)
@@ -447,7 +494,7 @@ struct e1000_info {
 #define FLAG_MSI_ENABLED                  (1 << 27)
 /* reserved (1 << 28) */
 #define FLAG_TSO_FORCE                    (1 << 29)
-#define FLAG_RX_RESTART_NOW               (1 << 30)
+#define FLAG_RESTART_NOW                  (1 << 30)
 #define FLAG_MSI_TEST_FAILED              (1 << 31)
 
 #define FLAG2_CRC_STRIPPING               (1 << 0)
@@ -463,6 +510,7 @@ struct e1000_info {
 #define FLAG2_NO_DISABLE_RX               (1 << 10)
 #define FLAG2_PCIM2PCI_ARBITER_WA         (1 << 11)
 #define FLAG2_DFLT_CRC_STRIPPING          (1 << 12)
+#define FLAG2_CHECK_RX_HWTSTAMP           (1 << 13)
 
 #define E1000_RX_DESC_PS(R, i)     \
        (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -512,8 +560,6 @@ extern void e1000e_write_itr(struct e1000_adapter *adapter, u32 itr);
 
 extern unsigned int copybreak;
 
-extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
-
 extern const struct e1000_info e1000_82571_info;
 extern const struct e1000_info e1000_82572_info;
 extern const struct e1000_info e1000_82573_info;
@@ -530,8 +576,6 @@ extern const struct e1000_info e1000_es2_info;
 extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
                                         u32 pba_num_size);
 
-extern s32  e1000e_commit_phy(struct e1000_hw *hw);
-
 extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
 
 extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
@@ -605,7 +649,7 @@ extern s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset,
                                            u16 data);
 extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
 extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
+extern s32 e1000e_get_cfg_done_generic(struct e1000_hw *hw);
 extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
 extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
 extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
@@ -659,6 +703,9 @@ extern s32 e1000_check_polarity_ife(struct e1000_hw *hw);
 extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
 extern s32 e1000_check_polarity_igp(struct e1000_hw *hw);
 extern bool e1000_check_phy_82574(struct e1000_hw *hw);
+extern s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
+extern void e1000e_ptp_init(struct e1000_adapter *adapter);
+extern void e1000e_ptp_remove(struct e1000_adapter *adapter);
 
 static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
 {
@@ -685,11 +732,6 @@ static inline s32 e1e_wphy_locked(struct e1000_hw *hw, u32 offset, u16 data)
        return hw->phy.ops.write_reg_locked(hw, offset, data);
 }
 
-static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
-{
-       return hw->phy.ops.get_cable_length(hw);
-}
-
 extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
 extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
 extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
index f95bc6ee1c227c89a2e158fde491dc03ef173b4b..58df18c2efc22cfc32b403e72452044eb41f013b 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/vmalloc.h>
+#include <linux/mdio.h>
 
 #include "e1000.h"
 
@@ -98,7 +99,6 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
        E1000_STAT("rx_flow_control_xoff", stats.xoffrxc),
        E1000_STAT("tx_flow_control_xon", stats.xontxc),
        E1000_STAT("tx_flow_control_xoff", stats.xofftxc),
-       E1000_STAT("rx_long_byte_count", stats.gorc),
        E1000_STAT("rx_csum_offload_good", hw_csum_good),
        E1000_STAT("rx_csum_offload_errors", hw_csum_err),
        E1000_STAT("rx_header_split", rx_hdr_split),
@@ -108,6 +108,9 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
        E1000_STAT("dropped_smbus", stats.mgpdc),
        E1000_STAT("rx_dma_failed", rx_dma_failed),
        E1000_STAT("tx_dma_failed", tx_dma_failed),
+       E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+       E1000_STAT("uncorr_ecc_errors", uncorr_errors),
+       E1000_STAT("corr_ecc_errors", corr_errors),
 };
 
 #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
@@ -759,8 +762,9 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data,
                                      (test[pat] & write));
                val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset);
                if (val != (test[pat] & write & mask)) {
-                       e_err("pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
-                             reg + offset, val, (test[pat] & write & mask));
+                       e_err("pattern test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n",
+                             reg + (offset << 2), val,
+                             (test[pat] & write & mask));
                        *data = reg;
                        return 1;
                }
@@ -775,7 +779,7 @@ static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data,
        __ew32(&adapter->hw, reg, write & mask);
        val = __er32(&adapter->hw, reg);
        if ((write & mask) != (val & mask)) {
-               e_err("set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
+               e_err("set/check test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n",
                      reg, (val & mask), (write & mask));
                *data = reg;
                return 1;
@@ -883,12 +887,20 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                    E1000_FWSM_WLOCK_MAC_SHIFT;
 
        for (i = 0; i < mac->rar_entry_count; i++) {
-               /* Cannot test write-protected SHRAL[n] registers */
-               if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
-                       continue;
+               if (mac->type == e1000_pch_lpt) {
+                       /* Cannot test write-protected SHRAL[n] registers */
+                       if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
+                               continue;
+
+                       /* SHRAH[9] different than the others */
+                       if (i == 10)
+                               mask |= (1 << 30);
+                       else
+                               mask &= ~(1 << 30);
+               }
 
-               REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
-                                      mask, 0xFFFFFFFF);
+               REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask,
+                                      0xFFFFFFFF);
        }
 
        for (i = 0; i < mac->mta_reg_count; i++)
@@ -1309,7 +1321,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
                phy_reg |= 0x006;
                e1e_wphy(hw, PHY_REG(2, 21), phy_reg);
                /* Assert SW reset for above settings to take effect */
-               e1000e_commit_phy(hw);
+               hw->phy.ops.commit(hw);
                mdelay(1);
                /* Force Full Duplex */
                e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
@@ -1393,7 +1405,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 ctrl = er32(CTRL);
-       int link = 0;
+       int link;
 
        /* special requirements for 82571/82572 fiber adapters */
 
@@ -1530,7 +1542,8 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
                if (phy_reg & MII_CR_LOOPBACK) {
                        phy_reg &= ~MII_CR_LOOPBACK;
                        e1e_wphy(hw, PHY_CONTROL, phy_reg);
-                       e1000e_commit_phy(hw);
+                       if (hw->phy.ops.commit)
+                               hw->phy.ops.commit(hw);
                }
                break;
        }
@@ -2051,6 +2064,171 @@ static int e1000_get_rxnfc(struct net_device *netdev,
        }
 }
 
+static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u16 cap_addr, adv_addr, lpa_addr, pcs_stat_addr, phy_data, lpi_ctrl;
+       u32 status, ret_val;
+
+       if (!(adapter->flags & FLAG_IS_ICH) ||
+           !(adapter->flags2 & FLAG2_HAS_EEE))
+               return -EOPNOTSUPP;
+
+       switch (hw->phy.type) {
+       case e1000_phy_82579:
+               cap_addr = I82579_EEE_CAPABILITY;
+               adv_addr = I82579_EEE_ADVERTISEMENT;
+               lpa_addr = I82579_EEE_LP_ABILITY;
+               pcs_stat_addr = I82579_EEE_PCS_STATUS;
+               break;
+       case e1000_phy_i217:
+               cap_addr = I217_EEE_CAPABILITY;
+               adv_addr = I217_EEE_ADVERTISEMENT;
+               lpa_addr = I217_EEE_LP_ABILITY;
+               pcs_stat_addr = I217_EEE_PCS_STATUS;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               return -EBUSY;
+
+       /* EEE Capability */
+       ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data);
+       if (ret_val)
+               goto release;
+       edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data);
+
+       /* EEE Advertised */
+       ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &phy_data);
+       if (ret_val)
+               goto release;
+       edata->advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+       /* EEE Link Partner Advertised */
+       ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data);
+       if (ret_val)
+               goto release;
+       edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+       /* EEE PCS Status */
+       ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data);
+       if (hw->phy.type == e1000_phy_82579)
+               phy_data <<= 8;
+
+release:
+       hw->phy.ops.release(hw);
+       if (ret_val)
+               return -ENODATA;
+
+       e1e_rphy(hw, I82579_LPI_CTRL, &lpi_ctrl);
+       status = er32(STATUS);
+
+       /* Result of the EEE auto negotiation - there is no register that
+        * has the status of the EEE negotiation so do a best-guess based
+        * on whether both Tx and Rx LPI indications have been received or
+        * base it on the link speed, the EEE advertised speeds on both ends
+        * and the speeds on which EEE is enabled locally.
+        */
+       if (((phy_data & E1000_EEE_TX_LPI_RCVD) &&
+            (phy_data & E1000_EEE_RX_LPI_RCVD)) ||
+           ((status & E1000_STATUS_SPEED_100) &&
+            (edata->advertised & ADVERTISED_100baseT_Full) &&
+            (edata->lp_advertised & ADVERTISED_100baseT_Full) &&
+            (lpi_ctrl & I82579_LPI_CTRL_100_ENABLE)) ||
+           ((status & E1000_STATUS_SPEED_1000) &&
+            (edata->advertised & ADVERTISED_1000baseT_Full) &&
+            (edata->lp_advertised & ADVERTISED_1000baseT_Full) &&
+            (lpi_ctrl & I82579_LPI_CTRL_1000_ENABLE)))
+               edata->eee_active = true;
+
+       edata->eee_enabled = !hw->dev_spec.ich8lan.eee_disable;
+       edata->tx_lpi_enabled = true;
+       edata->tx_lpi_timer = er32(LPIC) >> E1000_LPIC_LPIET_SHIFT;
+
+       return 0;
+}
+
+static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       struct ethtool_eee eee_curr;
+       s32 ret_val;
+
+       if (!(adapter->flags & FLAG_IS_ICH) ||
+           !(adapter->flags2 & FLAG2_HAS_EEE))
+               return -EOPNOTSUPP;
+
+       ret_val = e1000e_get_eee(netdev, &eee_curr);
+       if (ret_val)
+               return ret_val;
+
+       if (eee_curr.advertised != edata->advertised) {
+               e_err("Setting EEE advertisement is not supported\n");
+               return -EINVAL;
+       }
+
+       if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
+               e_err("Setting EEE tx-lpi is not supported\n");
+               return -EINVAL;
+       }
+
+       if (eee_curr.tx_lpi_timer != edata->tx_lpi_timer) {
+               e_err("Setting EEE Tx LPI timer is not supported\n");
+               return -EINVAL;
+       }
+
+       if (hw->dev_spec.ich8lan.eee_disable != !edata->eee_enabled) {
+               hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
+
+               /* reset the link */
+               if (netif_running(netdev))
+                       e1000e_reinit_locked(adapter);
+               else
+                       e1000e_reset(adapter);
+       }
+
+       return 0;
+}
+
+static int e1000e_get_ts_info(struct net_device *netdev,
+                             struct ethtool_ts_info *info)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       ethtool_op_get_ts_info(netdev, info);
+
+       if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+               return 0;
+
+       info->so_timestamping |= (SOF_TIMESTAMPING_TX_HARDWARE |
+                                 SOF_TIMESTAMPING_RX_HARDWARE |
+                                 SOF_TIMESTAMPING_RAW_HARDWARE);
+
+       info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+
+       info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
+                           (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+                           (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+                           (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+                           (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+                           (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+                           (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+                           (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+                           (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+                           (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+                           (1 << HWTSTAMP_FILTER_ALL));
+
+       if (adapter->ptp_clock)
+               info->phc_index = ptp_clock_index(adapter->ptp_clock);
+
+       return 0;
+}
+
 static const struct ethtool_ops e1000_ethtool_ops = {
        .get_settings           = e1000_get_settings,
        .set_settings           = e1000_set_settings,
@@ -2078,7 +2256,9 @@ static const struct ethtool_ops e1000_ethtool_ops = {
        .get_coalesce           = e1000_get_coalesce,
        .set_coalesce           = e1000_set_coalesce,
        .get_rxnfc              = e1000_get_rxnfc,
-       .get_ts_info            = ethtool_op_get_ts_info,
+       .get_ts_info            = e1000e_get_ts_info,
+       .get_eee                = e1000e_get_eee,
+       .set_eee                = e1000e_set_eee,
 };
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)
index cf217777586c246561120c0877516f22d3ff6b89..f32b19af9a7204421a526812f8a21d50ace2612f 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #ifndef _E1000_HW_H_
 #define _E1000_HW_H_
 
-#include <linux/types.h>
+#include "defines.h"
 
 struct e1000_hw;
-struct e1000_adapter;
-
-#include "defines.h"
 
 enum e1e_registers {
        E1000_CTRL     = 0x00000, /* Device Control - RW */
@@ -60,8 +57,10 @@ enum e1e_registers {
        E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
        E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
        E1000_IVAR     = 0x000E4, /* Interrupt Vector Allocation - RW */
+       E1000_FEXTNVM7  = 0x000E4, /* Future Extended NVM 7 - RW */
        E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
 #define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
+       E1000_LPIC     = 0x000FC, /* Low Power Idle Control - RW */
        E1000_RCTL     = 0x00100, /* Rx Control - RW */
        E1000_FCTTV    = 0x00170, /* Flow Control Transmit Timer Value - RW */
        E1000_TXCW     = 0x00178, /* Tx Configuration Word - RW */
@@ -77,6 +76,7 @@ enum e1e_registers {
 #define E1000_POEMB    E1000_PHY_CTRL  /* PHY OEM Bits */
        E1000_PBA      = 0x01000, /* Packet Buffer Allocation - RW */
        E1000_PBS      = 0x01008, /* Packet Buffer Size */
+       E1000_PBECCSTS = 0x0100C, /* Packet Buffer ECC Status - RW */
        E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
        E1000_EEWR     = 0x0102C, /* EEPROM Write Register - RW */
        E1000_FLOP     = 0x0103C, /* FLASH Opcode Register */
@@ -191,6 +191,10 @@ enum e1e_registers {
        E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
        E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
        E1000_ICRXOC   = 0x04124, /* Irq Cause Receiver Overrun Count */
+       E1000_PCS_LCTL = 0x04208, /* PCS Link Control - RW */
+       E1000_PCS_LSTAT = 0x0420C, /* PCS Link Status - RO */
+       E1000_PCS_ANADV = 0x04218, /* AN advertisement - RW */
+       E1000_PCS_LPAB = 0x0421C, /* Link Partner Ability - RW */
        E1000_RXCSUM   = 0x05000, /* Rx Checksum Control - RW */
        E1000_RFCTL    = 0x05008, /* Receive Filter Control */
        E1000_MTA      = 0x05200, /* Multicast Table Array - RW Array */
@@ -236,6 +240,17 @@ enum e1e_registers {
 #define E1000_PCH_RAICC(_n)    (E1000_PCH_RAICC_BASE + ((_n) * 4))
 #define E1000_CRC_OFFSET       E1000_PCH_RAICC_BASE
        E1000_HICR      = 0x08F00, /* Host Interface Control */
+       E1000_SYSTIML   = 0x0B600, /* System time register Low - RO */
+       E1000_SYSTIMH   = 0x0B604, /* System time register High - RO */
+       E1000_TIMINCA   = 0x0B608, /* Increment attributes register - RW */
+       E1000_TSYNCTXCTL = 0x0B614, /* Tx Time Sync Control register - RW */
+       E1000_TXSTMPL   = 0x0B618, /* Tx timestamp value Low - RO */
+       E1000_TXSTMPH   = 0x0B61C, /* Tx timestamp value High - RO */
+       E1000_TSYNCRXCTL = 0x0B620, /* Rx Time Sync Control register - RW */
+       E1000_RXSTMPL   = 0x0B624, /* Rx timestamp Low - RO */
+       E1000_RXSTMPH   = 0x0B628, /* Rx timestamp High - RO */
+       E1000_RXMTRL    = 0x0B634, /* Timesync Rx EtherType and Msg Type - RW */
+       E1000_RXUDP     = 0x0B638, /* Timesync Rx UDP Port - RW */
 };
 
 #define E1000_MAX_PHY_ADDR             4
@@ -373,13 +388,11 @@ enum e1e_registers {
 #define E1000_DEV_ID_82573L                    0x109A
 #define E1000_DEV_ID_82574L                    0x10D3
 #define E1000_DEV_ID_82574LA                   0x10F6
-#define E1000_DEV_ID_82583V                     0x150C
-
+#define E1000_DEV_ID_82583V                    0x150C
 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT    0x1096
 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT    0x1098
 #define E1000_DEV_ID_80003ES2LAN_COPPER_SPT    0x10BA
 #define E1000_DEV_ID_80003ES2LAN_SERDES_SPT    0x10BB
-
 #define E1000_DEV_ID_ICH8_82567V_3             0x1501
 #define E1000_DEV_ID_ICH8_IGP_M_AMT            0x1049
 #define E1000_DEV_ID_ICH8_IGP_AMT              0x104A
@@ -414,12 +427,12 @@ enum e1e_registers {
 #define E1000_DEV_ID_PCH_LPTLP_I218_LM         0x155A
 #define E1000_DEV_ID_PCH_LPTLP_I218_V          0x1559
 
-#define E1000_REVISION_4 4
+#define E1000_REVISION_4       4
 
-#define E1000_FUNC_1 1
+#define E1000_FUNC_1           1
 
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0      0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1      3
 
 enum e1000_mac_type {
        e1000_82571,
@@ -524,16 +537,6 @@ enum e1000_serdes_link_state {
        e1000_serdes_link_forced_up
 };
 
-/* Receive Descriptor */
-struct e1000_rx_desc {
-       __le64 buffer_addr; /* Address of the descriptor's data buffer */
-       __le16 length;      /* Length of data DMAed into data buffer */
-       __le16 csum;    /* Packet checksum */
-       u8  status;      /* Descriptor status */
-       u8  errors;      /* Descriptor Errors */
-       __le16 special;
-};
-
 /* Receive Descriptor - Extended */
 union e1000_rx_desc_extended {
        struct {
@@ -656,7 +659,7 @@ struct e1000_data_desc {
                struct {
                        u8 status;     /* Descriptor status */
                        u8 popts;      /* Packet Options */
-                       __le16 special;   /* */
+                       __le16 special;
                } fields;
        } upper;
 };
@@ -752,7 +755,7 @@ struct e1000_host_command_header {
        u8 checksum;
 };
 
-#define E1000_HI_MAX_DATA_LENGTH     252
+#define E1000_HI_MAX_DATA_LENGTH       252
 struct e1000_host_command_info {
        struct e1000_host_command_header command_header;
        u8 command_data[E1000_HI_MAX_DATA_LENGTH];
@@ -767,13 +770,13 @@ struct e1000_host_mng_command_header {
        u16 command_length;
 };
 
-#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+#define E1000_HI_MAX_MNG_DATA_LENGTH   0x6F8
 struct e1000_host_mng_command_info {
        struct e1000_host_mng_command_header command_header;
        u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
 };
 
-/* Function pointers and static data for the MAC. */
+/* Function pointers for the MAC. */
 struct e1000_mac_operations {
        s32  (*id_led_init)(struct e1000_hw *);
        s32  (*blink_led)(struct e1000_hw *);
index 976336547607e31caef68c8eaf528ddac78682da..58547b8abe3db3e3bdf75f06a1698dd9154f9afe 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #define HV_PM_CTRL             PHY_REG(770, 17)
 #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
 
-/* PHY Low Power Idle Control */
-#define I82579_LPI_CTRL                                PHY_REG(772, 20)
-#define I82579_LPI_CTRL_ENABLE_MASK            0x6000
-#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT   0x80
-
-/* EMI Registers */
-#define I82579_EMI_ADDR         0x10
-#define I82579_EMI_DATA         0x11
-#define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */
-#define I82579_MSE_THRESHOLD    0x084F /* Mean Square Error Threshold */
-#define I82579_MSE_LINK_DOWN    0x2411 /* MSE count before dropping link */
-#define I217_EEE_ADVERTISEMENT  0x8001 /* IEEE MMD Register 7.60 */
-#define I217_EEE_LP_ABILITY     0x8002 /* IEEE MMD Register 7.61 */
-#define I217_EEE_100_SUPPORTED  (1 << 1)       /* 100BaseTx EEE supported */
-
 /* Intel Rapid Start Technology Support */
 #define I217_PROXY_CTRL                 BM_PHY_REG(BM_WUC_PAGE, 70)
 #define I217_PROXY_CTRL_AUTO_DISABLE    0x0080
@@ -252,7 +237,6 @@ union ich8_flash_protected_range {
        u32 regval;
 };
 
-static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
 static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
@@ -264,9 +248,7 @@ static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
                                         u16 *data);
 static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
                                         u8 size, u16 *data);
-static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
 static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
-static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
 static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
 static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
 static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
@@ -278,7 +260,7 @@ static s32 e1000_led_off_pchlan(struct e1000_hw *hw);
 static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
 static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
 static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
-static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
+static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
 static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
@@ -378,10 +360,15 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_reg;
 
+       /* Gate automatic PHY configuration by hardware on managed and
+        * non-managed 82579 and newer adapters.
+        */
+       e1000_gate_hw_phy_config_ich8lan(hw, true);
+
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val) {
                e_dbg("Failed to initialize PHY flow\n");
-               return ret_val;
+               goto out;
        }
 
        /* The MAC-PHY interconnect may be in SMBus mode.  If the PHY is
@@ -402,13 +389,6 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 
                /* fall-through */
        case e1000_pch2lan:
-               /* Gate automatic PHY configuration by hardware on
-                * non-managed 82579
-                */
-               if ((hw->mac.type == e1000_pch2lan) &&
-                   !(fwsm & E1000_ICH_FWSM_FW_VALID))
-                       e1000_gate_hw_phy_config_ich8lan(hw, true);
-
                if (e1000_phy_is_accessible_pchlan(hw)) {
                        if (hw->mac.type == e1000_pch_lpt) {
                                /* Unforce SMBus mode in PHY */
@@ -443,6 +423,15 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
                mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
                ew32(FEXTNVM3, mac_reg);
 
+               if (hw->mac.type == e1000_pch_lpt) {
+                       /* Toggling LANPHYPC brings the PHY out of SMBus mode
+                        * So ensure that the MAC is also out of SMBus mode
+                        */
+                       mac_reg = er32(CTRL_EXT);
+                       mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+                       ew32(CTRL_EXT, mac_reg);
+               }
+
                /* Toggle LANPHYPC Value bit */
                mac_reg = er32(CTRL);
                mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
@@ -476,6 +465,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
         */
        ret_val = e1000e_phy_hw_reset_generic(hw);
 
+out:
        /* Ungate automatic PHY configuration on non-managed 82579 */
        if ((hw->mac.type == e1000_pch2lan) &&
            !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
@@ -495,7 +485,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
 {
        struct e1000_phy_info *phy = &hw->phy;
-       s32 ret_val = 0;
+       s32 ret_val;
 
        phy->addr                     = 1;
        phy->reset_delay_us           = 100;
@@ -778,68 +768,143 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
        if (mac->type == e1000_ich8lan)
                e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
 
-       /* Gate automatic PHY configuration by hardware on managed
-        * 82579 and i217
-        */
-       if ((mac->type == e1000_pch2lan || mac->type == e1000_pch_lpt) &&
-           (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
-               e1000_gate_hw_phy_config_ich8lan(hw, true);
-
        return 0;
 }
 
+/**
+ *  __e1000_access_emi_reg_locked - Read/write EMI register
+ *  @hw: pointer to the HW structure
+ *  @addr: EMI address to program
+ *  @data: pointer to value to read/write from/to the EMI address
+ *  @read: boolean flag to indicate read or write
+ *
+ *  This helper function assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address,
+                                        u16 *data, bool read)
+{
+       s32 ret_val;
+
+       ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, address);
+       if (ret_val)
+               return ret_val;
+
+       if (read)
+               ret_val = e1e_rphy_locked(hw, I82579_EMI_DATA, data);
+       else
+               ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, *data);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_read_emi_reg_locked - Read Extended Management Interface register
+ *  @hw: pointer to the HW structure
+ *  @addr: EMI address to program
+ *  @data: value to be read from the EMI address
+ *
+ *  Assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
+{
+       return __e1000_access_emi_reg_locked(hw, addr, data, true);
+}
+
+/**
+ *  e1000_write_emi_reg_locked - Write Extended Management Interface register
+ *  @hw: pointer to the HW structure
+ *  @addr: EMI address to program
+ *  @data: value to be written to the EMI address
+ *
+ *  Assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+static s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
+{
+       return __e1000_access_emi_reg_locked(hw, addr, &data, false);
+}
+
 /**
  *  e1000_set_eee_pchlan - Enable/disable EEE support
  *  @hw: pointer to the HW structure
  *
- *  Enable/disable EEE based on setting in dev_spec structure.  The bits in
- *  the LPI Control register will remain set only if/when link is up.
+ *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
+ *  the link and the EEE capabilities of the link partner.  The LPI Control
+ *  register bits will remain set only if/when link is up.
  **/
 static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
 {
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-       s32 ret_val = 0;
-       u16 phy_reg;
+       s32 ret_val;
+       u16 lpi_ctrl;
 
        if ((hw->phy.type != e1000_phy_82579) &&
            (hw->phy.type != e1000_phy_i217))
                return 0;
 
-       ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+       ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
 
-       if (dev_spec->eee_disable)
-               phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
-       else
-               phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
-
-       ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
+       ret_val = e1e_rphy_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
        if (ret_val)
-               return ret_val;
+               goto release;
+
+       /* Clear bits that enable EEE in various speeds */
+       lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
+
+       /* Enable EEE if not disabled by user */
+       if (!dev_spec->eee_disable) {
+               u16 lpa, pcs_status, data;
 
-       if ((hw->phy.type == e1000_phy_i217) && !dev_spec->eee_disable) {
                /* Save off link partner's EEE ability */
-               ret_val = hw->phy.ops.acquire(hw);
-               if (ret_val)
-                       return ret_val;
-               ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
-                                         I217_EEE_LP_ABILITY);
+               switch (hw->phy.type) {
+               case e1000_phy_82579:
+                       lpa = I82579_EEE_LP_ABILITY;
+                       pcs_status = I82579_EEE_PCS_STATUS;
+                       break;
+               case e1000_phy_i217:
+                       lpa = I217_EEE_LP_ABILITY;
+                       pcs_status = I217_EEE_PCS_STATUS;
+                       break;
+               default:
+                       ret_val = -E1000_ERR_PHY;
+                       goto release;
+               }
+               ret_val = e1000_read_emi_reg_locked(hw, lpa,
+                                                   &dev_spec->eee_lp_ability);
                if (ret_val)
                        goto release;
-               e1e_rphy_locked(hw, I82579_EMI_DATA, &dev_spec->eee_lp_ability);
 
-               /* EEE is not supported in 100Half, so ignore partner's EEE
-                * in 100 ability if full-duplex is not advertised.
+               /* Enable EEE only for speeds in which the link partner is
+                * EEE capable.
                 */
-               e1e_rphy_locked(hw, PHY_LP_ABILITY, &phy_reg);
-               if (!(phy_reg & NWAY_LPAR_100TX_FD_CAPS))
-                       dev_spec->eee_lp_ability &= ~I217_EEE_100_SUPPORTED;
-release:
-               hw->phy.ops.release(hw);
+               if (dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
+                       lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
+
+               if (dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
+                       e1e_rphy_locked(hw, PHY_LP_ABILITY, &data);
+                       if (data & NWAY_LPAR_100TX_FD_CAPS)
+                               lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
+                       else
+                               /* EEE is not supported in 100Half, so ignore
+                                * partner's EEE in 100 ability if full-duplex
+                                * is not advertised.
+                                */
+                               dev_spec->eee_lp_ability &=
+                                   ~I82579_EEE_100_SUPPORTED;
+               }
+
+               /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
+               ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
+               if (ret_val)
+                       goto release;
        }
 
-       return 0;
+       ret_val = e1e_wphy_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
+release:
+       hw->phy.ops.release(hw);
+
+       return ret_val;
 }
 
 /**
@@ -1322,7 +1387,7 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
        u32 strap = er32(STRAP);
        u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
            E1000_STRAP_SMT_FREQ_SHIFT;
-       s32 ret_val = 0;
+       s32 ret_val;
 
        strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
 
@@ -1558,7 +1623,7 @@ release:
  **/
 s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
 {
-       s32 ret_val = 0;
+       s32 ret_val;
        u32 ctrl_reg = 0;
        u32 ctrl_ext = 0;
        u32 reg = 0;
@@ -1757,6 +1822,11 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
        if (ret_val)
                goto release;
        ret_val = e1e_wphy_locked(hw, BM_PORT_GEN_CFG, phy_data & 0x00FF);
+       if (ret_val)
+               goto release;
+
+       /* set MSE higher to enable link to stay up when noise is high */
+       ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034);
 release:
        hw->phy.ops.release(hw);
 
@@ -1983,22 +2053,18 @@ static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
 
        /* Set MDIO slow mode before any other MDIO access */
        ret_val = e1000_set_mdio_slow_mode_hv(hw);
+       if (ret_val)
+               return ret_val;
 
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
-       ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_THRESHOLD);
-       if (ret_val)
-               goto release;
        /* set MSE higher to enable link to stay up when noise is high */
-       ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0034);
-       if (ret_val)
-               goto release;
-       ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_LINK_DOWN);
+       ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034);
        if (ret_val)
                goto release;
        /* drop link after 5 times MSE threshold was reached */
-       ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0005);
+       ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005);
 release:
        hw->phy.ops.release(hw);
 
@@ -2172,10 +2238,9 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
                ret_val = hw->phy.ops.acquire(hw);
                if (ret_val)
                        return ret_val;
-               ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
-                                         I82579_LPI_UPDATE_TIMER);
-               if (!ret_val)
-                       ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x1387);
+               ret_val = e1000_write_emi_reg_locked(hw,
+                                                    I82579_LPI_UPDATE_TIMER,
+                                                    0x1387);
                hw->phy.ops.release(hw);
        }
 
@@ -2219,7 +2284,7 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
  **/
 static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
 {
-       s32 ret_val = 0;
+       s32 ret_val;
        u16 oem_reg;
 
        ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg);
@@ -2277,6 +2342,8 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
 
                /* When LPLU is enabled, we should disable SmartSpeed */
                ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+               if (ret_val)
+                       return ret_val;
                data &= ~IGP01E1000_PSCFR_SMART_SPEED;
                ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
                if (ret_val)
@@ -2949,19 +3016,32 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
 {
        s32 ret_val;
        u16 data;
+       u16 word;
+       u16 valid_csum_mask;
 
-       /* Read 0x19 and check bit 6.  If this bit is 0, the checksum
-        * needs to be fixed.  This bit is an indication that the NVM
-        * was prepared by OEM software and did not calculate the
-        * checksum...a likely scenario.
+       /* Read NVM and check Invalid Image CSUM bit.  If this bit is 0,
+        * the checksum needs to be fixed.  This bit is an indication that
+        * the NVM was prepared by OEM software and did not calculate
+        * the checksum...a likely scenario.
         */
-       ret_val = e1000_read_nvm(hw, 0x19, 1, &data);
+       switch (hw->mac.type) {
+       case e1000_pch_lpt:
+               word = NVM_COMPAT;
+               valid_csum_mask = NVM_COMPAT_VALID_CSUM;
+               break;
+       default:
+               word = NVM_FUTURE_INIT_WORD1;
+               valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM;
+               break;
+       }
+
+       ret_val = e1000_read_nvm(hw, word, 1, &data);
        if (ret_val)
                return ret_val;
 
-       if (!(data & 0x40)) {
-               data |= 0x40;
-               ret_val = e1000_write_nvm(hw, 0x19, 1, &data);
+       if (!(data & valid_csum_mask)) {
+               data |= valid_csum_mask;
+               ret_val = e1000_write_nvm(hw, word, 1, &data);
                if (ret_val)
                        return ret_val;
                ret_val = e1000e_update_nvm_checksum(hw);
@@ -3624,6 +3704,17 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
        if (hw->mac.type == e1000_ich8lan)
                reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
        ew32(RFCTL, reg);
+
+       /* Enable ECC on Lynxpoint */
+       if (hw->mac.type == e1000_pch_lpt) {
+               reg = er32(PBECCSTS);
+               reg |= E1000_PBECCSTS_ECC_ENABLE;
+               ew32(PBECCSTS, reg);
+
+               reg = er32(CTRL);
+               reg |= E1000_CTRL_MEHE;
+               ew32(CTRL, reg);
+       }
 }
 
 /**
@@ -3964,8 +4055,7 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
        if (ret_val)
                return;
        reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
-       ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
-                                      reg_data);
+       e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, reg_data);
 }
 
 /**
@@ -4000,19 +4090,20 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
                if (!dev_spec->eee_disable) {
                        u16 eee_advert;
 
-                       ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
-                                                 I217_EEE_ADVERTISEMENT);
+                       ret_val =
+                           e1000_read_emi_reg_locked(hw,
+                                                     I217_EEE_ADVERTISEMENT,
+                                                     &eee_advert);
                        if (ret_val)
                                goto release;
-                       e1e_rphy_locked(hw, I82579_EMI_DATA, &eee_advert);
 
                        /* Disable LPLU if both link partners support 100BaseT
                         * EEE and 100Full is advertised on both ends of the
                         * link.
                         */
-                       if ((eee_advert & I217_EEE_100_SUPPORTED) &&
+                       if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
                            (dev_spec->eee_lp_ability &
-                            I217_EEE_100_SUPPORTED) &&
+                            I82579_EEE_100_SUPPORTED) &&
                            (hw->phy.autoneg_advertised & ADVERTISE_100_FULL))
                                phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
                                              E1000_PHY_CTRL_NOND0A_LPLU);
@@ -4287,7 +4378,7 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
        u32 bank = 0;
        u32 status;
 
-       e1000e_get_cfg_done(hw);
+       e1000e_get_cfg_done_generic(hw);
 
        /* Wait for indication from h/w that it has completed basic config */
        if (hw->mac.type >= e1000_ich10lan) {
@@ -4520,6 +4611,7 @@ const struct e1000_info e1000_pch2_info = {
        .mac                    = e1000_pch2lan,
        .flags                  = FLAG_IS_ICH
                                  | FLAG_HAS_WOL
+                                 | FLAG_HAS_HW_TIMESTAMP
                                  | FLAG_HAS_CTRLEXT_ON_LOAD
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_FLASH
@@ -4528,7 +4620,7 @@ const struct e1000_info e1000_pch2_info = {
        .flags2                 = FLAG2_HAS_PHY_STATS
                                  | FLAG2_HAS_EEE,
        .pba                    = 26,
-       .max_hw_frame_size      = DEFAULT_JUMBO,
+       .max_hw_frame_size      = 9018,
        .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
@@ -4539,6 +4631,7 @@ const struct e1000_info e1000_pch_lpt_info = {
        .mac                    = e1000_pch_lpt,
        .flags                  = FLAG_IS_ICH
                                  | FLAG_HAS_WOL
+                                 | FLAG_HAS_HW_TIMESTAMP
                                  | FLAG_HAS_CTRLEXT_ON_LOAD
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_FLASH
@@ -4547,7 +4640,7 @@ const struct e1000_info e1000_pch_lpt_info = {
        .flags2                 = FLAG2_HAS_PHY_STATS
                                  | FLAG2_HAS_EEE,
        .pba                    = 26,
-       .max_hw_frame_size      = DEFAULT_JUMBO,
+       .max_hw_frame_size      = 9018,
        .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
index 54d9dafaf126609f4e9796b80f8d92de2c966745..0709f49f03353128ca7358cd1d72c356145bc87d 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -165,7 +165,7 @@ void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
 s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
 {
        u32 i;
-       s32 ret_val = 0;
+       s32 ret_val;
        u16 offset, nvm_alt_mac_addr_offset, nvm_data;
        u8 alt_mac_addr[ETH_ALEN];
 
@@ -1021,6 +1021,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
 {
        struct e1000_mac_info *mac = &hw->mac;
        s32 ret_val = 0;
+       u32 pcs_status_reg, pcs_adv_reg, pcs_lp_ability_reg, pcs_ctrl_reg;
        u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
        u16 speed, duplex;
 
@@ -1185,6 +1186,130 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
                }
        }
 
+       /* Check for the case where we have SerDes media and auto-neg is
+        * enabled.  In this case, we need to check and see if Auto-Neg
+        * has completed, and if so, how the PHY and link partner has
+        * flow control configured.
+        */
+       if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
+           mac->autoneg) {
+               /* Read the PCS_LSTS and check to see if AutoNeg
+                * has completed.
+                */
+               pcs_status_reg = er32(PCS_LSTAT);
+
+               if (!(pcs_status_reg & E1000_PCS_LSTS_AN_COMPLETE)) {
+                       e_dbg("PCS Auto Neg has not completed.\n");
+                       return ret_val;
+               }
+
+               /* The AutoNeg process has completed, so we now need to
+                * read both the Auto Negotiation Advertisement
+                * Register (PCS_ANADV) and the Auto_Negotiation Base
+                * Page Ability Register (PCS_LPAB) to determine how
+                * flow control was negotiated.
+                */
+               pcs_adv_reg = er32(PCS_ANADV);
+               pcs_lp_ability_reg = er32(PCS_LPAB);
+
+               /* Two bits in the Auto Negotiation Advertisement Register
+                * (PCS_ANADV) and two bits in the Auto Negotiation Base
+                * Page Ability Register (PCS_LPAB) determine flow control
+                * for both the PHY and the link partner.  The following
+                * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+                * 1999, describes these PAUSE resolution bits and how flow
+                * control is determined based upon these settings.
+                * NOTE:  DC = Don't Care
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+                *-------|---------|-------|---------|--------------------
+                *   0   |    0    |  DC   |   DC    | e1000_fc_none
+                *   0   |    1    |   0   |   DC    | e1000_fc_none
+                *   0   |    1    |   1   |    0    | e1000_fc_none
+                *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+                *   1   |    0    |   0   |   DC    | e1000_fc_none
+                *   1   |   DC    |   1   |   DC    | e1000_fc_full
+                *   1   |    1    |   0   |    0    | e1000_fc_none
+                *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+                *
+                * Are both PAUSE bits set to 1?  If so, this implies
+                * Symmetric Flow Control is enabled at both ends.  The
+                * ASM_DIR bits are irrelevant per the spec.
+                *
+                * For Symmetric Flow Control:
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+                *-------|---------|-------|---------|--------------------
+                *   1   |   DC    |   1   |   DC    | e1000_fc_full
+                *
+                */
+               if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+                   (pcs_lp_ability_reg & E1000_TXCW_PAUSE)) {
+                       /* Now we need to check if the user selected Rx ONLY
+                        * of pause frames.  In this case, we had to advertise
+                        * FULL flow control because we could not advertise Rx
+                        * ONLY. Hence, we must now check to see if we need to
+                        * turn OFF the TRANSMISSION of PAUSE frames.
+                        */
+                       if (hw->fc.requested_mode == e1000_fc_full) {
+                               hw->fc.current_mode = e1000_fc_full;
+                               e_dbg("Flow Control = FULL.\n");
+                       } else {
+                               hw->fc.current_mode = e1000_fc_rx_pause;
+                               e_dbg("Flow Control = Rx PAUSE frames only.\n");
+                       }
+               }
+               /* For receiving PAUSE frames ONLY.
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+                *-------|---------|-------|---------|--------------------
+                *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+                */
+               else if (!(pcs_adv_reg & E1000_TXCW_PAUSE) &&
+                        (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+                        (pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+                        (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+                       hw->fc.current_mode = e1000_fc_tx_pause;
+                       e_dbg("Flow Control = Tx PAUSE frames only.\n");
+               }
+               /* For transmitting PAUSE frames ONLY.
+                *
+                *   LOCAL DEVICE  |   LINK PARTNER
+                * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+                *-------|---------|-------|---------|--------------------
+                *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+                */
+               else if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+                        (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+                        !(pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+                        (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+                       hw->fc.current_mode = e1000_fc_rx_pause;
+                       e_dbg("Flow Control = Rx PAUSE frames only.\n");
+               } else {
+                       /* Per the IEEE spec, at this point flow control
+                        * should be disabled.
+                        */
+                       hw->fc.current_mode = e1000_fc_none;
+                       e_dbg("Flow Control = NONE.\n");
+               }
+
+               /* Now we call a subroutine to actually force the MAC
+                * controller to use the correct flow control settings.
+                */
+               pcs_ctrl_reg = er32(PCS_LCTL);
+               pcs_ctrl_reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+               ew32(PCS_LCTL, pcs_ctrl_reg);
+
+               ret_val = e1000e_force_mac_fc(hw);
+               if (ret_val) {
+                       e_dbg("Error forcing flow control settings\n");
+                       return ret_val;
+               }
+       }
+
        return 0;
 }
 
index 6dc47beb3adce59a46116bc37bc5e14ec931e109..4dae0dbda8375ebe9f93e2d3ec9da46f60b1935e 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index fbf75fdca99422743f35d3d9a114fcdef235563f..46a38a4d8da58384bce368aa4dd4569731772571 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -487,21 +487,88 @@ static int e1000_desc_unused(struct e1000_ring *ring)
        return ring->count + ring->next_to_clean - ring->next_to_use - 1;
 }
 
+/**
+ * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+ * @adapter: board private structure
+ * @hwtstamps: time stamp structure to update
+ * @systim: unsigned 64bit system time value.
+ *
+ * Convert the system time value stored in the RX/TXSTMP registers into a
+ * hwtstamp which can be used by the upper level time stamping functions.
+ *
+ * The 'systim_lock' spinlock is used to protect the consistency of the
+ * system time value. This is needed because reading the 64 bit time
+ * value involves reading two 32 bit registers. The first read latches the
+ * value.
+ **/
+static void e1000e_systim_to_hwtstamp(struct e1000_adapter *adapter,
+                                     struct skb_shared_hwtstamps *hwtstamps,
+                                     u64 systim)
+{
+       u64 ns;
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->systim_lock, flags);
+       ns = timecounter_cyc2time(&adapter->tc, systim);
+       spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+       memset(hwtstamps, 0, sizeof(*hwtstamps));
+       hwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * e1000e_rx_hwtstamp - utility function which checks for Rx time stamp
+ * @adapter: board private structure
+ * @status: descriptor extended error and status field
+ * @skb: particular skb to include time stamp
+ *
+ * If the time stamp is valid, convert it into the timecounter ns value
+ * and store that result into the shhwtstamps structure which is passed
+ * up the network stack.
+ **/
+static void e1000e_rx_hwtstamp(struct e1000_adapter *adapter, u32 status,
+                              struct sk_buff *skb)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u64 rxstmp;
+
+       if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP) ||
+           !(status & E1000_RXDEXT_STATERR_TST) ||
+           !(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
+               return;
+
+       /* The Rx time stamp registers contain the time stamp.  No other
+        * received packet will be time stamped until the Rx time stamp
+        * registers are read.  Because only one packet can be time stamped
+        * at a time, the register values must belong to this packet and
+        * therefore none of the other additional attributes need to be
+        * compared.
+        */
+       rxstmp = (u64)er32(RXSTMPL);
+       rxstmp |= (u64)er32(RXSTMPH) << 32;
+       e1000e_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), rxstmp);
+
+       adapter->flags2 &= ~FLAG2_CHECK_RX_HWTSTAMP;
+}
+
 /**
  * e1000_receive_skb - helper function to handle Rx indications
  * @adapter: board private structure
- * @status: descriptor status field as written by hardware
+ * @staterr: descriptor extended error and status field as written by hardware
  * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
  * @skb: pointer to sk_buff to be indicated to stack
  **/
 static void e1000_receive_skb(struct e1000_adapter *adapter,
                              struct net_device *netdev, struct sk_buff *skb,
-                             u8 status, __le16 vlan)
+                             u32 staterr, __le16 vlan)
 {
        u16 tag = le16_to_cpu(vlan);
+
+       e1000e_rx_hwtstamp(adapter, staterr, skb);
+
        skb->protocol = eth_type_trans(skb, netdev);
 
-       if (status & E1000_RXD_STAT_VP)
+       if (staterr & E1000_RXD_STAT_VP)
                __vlan_hwaccel_put_tag(skb, tag);
 
        napi_gro_receive(&adapter->napi, skb);
@@ -765,7 +832,7 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_ring *rx_ring,
        struct e1000_buffer *buffer_info;
        struct sk_buff *skb;
        unsigned int i;
-       unsigned int bufsz = 256 - 16 /* for skb_reserve */;
+       unsigned int bufsz = 256 - 16;  /* for skb_reserve */
 
        i = rx_ring->next_to_use;
        buffer_info = &rx_ring->buffer_info[i];
@@ -1091,6 +1158,41 @@ static void e1000_print_hw_hang(struct work_struct *work)
                e_err("Try turning off Tx pause (flow control) via ethtool\n");
 }
 
+/**
+ * e1000e_tx_hwtstamp_work - check for Tx time stamp
+ * @work: pointer to work struct
+ *
+ * This work function polls the TSYNCTXCTL valid bit to determine when a
+ * timestamp has been taken for the current stored skb.  The timestamp must
+ * be for this skb because only one such packet is allowed in the queue.
+ */
+static void e1000e_tx_hwtstamp_work(struct work_struct *work)
+{
+       struct e1000_adapter *adapter = container_of(work, struct e1000_adapter,
+                                                    tx_hwtstamp_work);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (!adapter->tx_hwtstamp_skb)
+               return;
+
+       if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
+               struct skb_shared_hwtstamps shhwtstamps;
+               u64 txstmp;
+
+               txstmp = er32(TXSTMPL);
+               txstmp |= (u64)er32(TXSTMPH) << 32;
+
+               e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
+
+               skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
+               dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+               adapter->tx_hwtstamp_skb = NULL;
+       } else {
+               /* reschedule to check later */
+               schedule_work(&adapter->tx_hwtstamp_work);
+       }
+}
+
 /**
  * e1000_clean_tx_irq - Reclaim resources after transmit completes
  * @tx_ring: Tx descriptor ring
@@ -1345,8 +1447,8 @@ copydone:
                           cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
                        adapter->rx_hdr_split++;
 
-               e1000_receive_skb(adapter, netdev, skb,
-                                 staterr, rx_desc->wb.middle.vlan);
+               e1000_receive_skb(adapter, netdev, skb, staterr,
+                                 rx_desc->wb.middle.vlan);
 
 next_desc:
                rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
@@ -1671,13 +1773,30 @@ static irqreturn_t e1000_intr_msi(int irq, void *data)
                        /* disable receives */
                        u32 rctl = er32(RCTL);
                        ew32(RCTL, rctl & ~E1000_RCTL_EN);
-                       adapter->flags |= FLAG_RX_RESTART_NOW;
+                       adapter->flags |= FLAG_RESTART_NOW;
                }
                /* guard against interrupt when we're going down */
                if (!test_bit(__E1000_DOWN, &adapter->state))
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
+       /* Reset on uncorrectable ECC error */
+       if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) {
+               u32 pbeccsts = er32(PBECCSTS);
+
+               adapter->corr_errors +=
+                   pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+               adapter->uncorr_errors +=
+                   (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+                   E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+
+               /* Do the reset outside of interrupt context */
+               schedule_work(&adapter->reset_task);
+
+               /* return immediately since reset is imminent */
+               return IRQ_HANDLED;
+       }
+
        if (napi_schedule_prep(&adapter->napi)) {
                adapter->total_tx_bytes = 0;
                adapter->total_tx_packets = 0;
@@ -1734,13 +1853,30 @@ static irqreturn_t e1000_intr(int irq, void *data)
                        /* disable receives */
                        rctl = er32(RCTL);
                        ew32(RCTL, rctl & ~E1000_RCTL_EN);
-                       adapter->flags |= FLAG_RX_RESTART_NOW;
+                       adapter->flags |= FLAG_RESTART_NOW;
                }
                /* guard against interrupt when we're going down */
                if (!test_bit(__E1000_DOWN, &adapter->state))
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
+       /* Reset on uncorrectable ECC error */
+       if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) {
+               u32 pbeccsts = er32(PBECCSTS);
+
+               adapter->corr_errors +=
+                   pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+               adapter->uncorr_errors +=
+                   (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+                   E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+
+               /* Do the reset outside of interrupt context */
+               schedule_work(&adapter->reset_task);
+
+               /* return immediately since reset is imminent */
+               return IRQ_HANDLED;
+       }
+
        if (napi_schedule_prep(&adapter->napi)) {
                adapter->total_tx_bytes = 0;
                adapter->total_tx_packets = 0;
@@ -2104,6 +2240,8 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
        if (adapter->msix_entries) {
                ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
                ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+       } else if (hw->mac.type == e1000_pch_lpt) {
+               ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
        } else {
                ew32(IMS, IMS_ENABLE_MASK);
        }
@@ -2405,7 +2543,6 @@ static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
 
 static void e1000_set_itr(struct e1000_adapter *adapter)
 {
-       struct e1000_hw *hw = &adapter->hw;
        u16 current_itr;
        u32 new_itr = adapter->itr;
 
@@ -2468,10 +2605,7 @@ set_itr_now:
                if (adapter->msix_entries)
                        adapter->rx_ring->set_itr = 1;
                else
-                       if (new_itr)
-                               ew32(ITR, 1000000000 / (new_itr * 256));
-                       else
-                               ew32(ITR, 0);
+                       e1000e_write_itr(adapter, new_itr);
        }
 }
 
@@ -3013,7 +3147,7 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
 
        ew32(RCTL, rctl);
        /* just started the receive unit, no need to restart */
-       adapter->flags &= ~FLAG_RX_RESTART_NOW;
+       adapter->flags &= ~FLAG_RESTART_NOW;
 }
 
 /**
@@ -3108,18 +3242,23 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
                rxcsum &= ~E1000_RXCSUM_TUOFL;
        ew32(RXCSUM, rxcsum);
 
-       if (adapter->hw.mac.type == e1000_pch2lan) {
-               /* With jumbo frames, excessive C-state transition
-                * latencies result in dropped transactions.
-                */
-               if (adapter->netdev->mtu > ETH_DATA_LEN) {
+       /* With jumbo frames, excessive C-state transition latencies result
+        * in dropped transactions.
+        */
+       if (adapter->netdev->mtu > ETH_DATA_LEN) {
+               u32 lat =
+                   ((er32(PBA) & E1000_PBA_RXA_MASK) * 1024 -
+                    adapter->max_frame_size) * 8 / 1000;
+
+               if (adapter->flags & FLAG_IS_ICH) {
                        u32 rxdctl = er32(RXDCTL(0));
                        ew32(RXDCTL(0), rxdctl | 0x3);
-                       pm_qos_update_request(&adapter->netdev->pm_qos_req, 55);
-               } else {
-                       pm_qos_update_request(&adapter->netdev->pm_qos_req,
-                                             PM_QOS_DEFAULT_VALUE);
                }
+
+               pm_qos_update_request(&adapter->netdev->pm_qos_req, lat);
+       } else {
+               pm_qos_update_request(&adapter->netdev->pm_qos_req,
+                                     PM_QOS_DEFAULT_VALUE);
        }
 
        /* Enable Receives */
@@ -3307,6 +3446,241 @@ static void e1000e_setup_rss_hash(struct e1000_adapter *adapter)
        ew32(MRQC, mrqc);
 }
 
+/**
+ * e1000e_get_base_timinca - get default SYSTIM time increment attributes
+ * @adapter: board private structure
+ * @timinca: pointer to returned time increment attributes
+ *
+ * Get attributes for incrementing the System Time Register SYSTIML/H at
+ * the default base frequency, and set the cyclecounter shift value.
+ **/
+s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 incvalue, incperiod, shift;
+
+       /* Make sure clock is enabled on I217 before checking the frequency */
+       if ((hw->mac.type == e1000_pch_lpt) &&
+           !(er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_ENABLED) &&
+           !(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_ENABLED)) {
+               u32 fextnvm7 = er32(FEXTNVM7);
+
+               if (!(fextnvm7 & (1 << 0))) {
+                       ew32(FEXTNVM7, fextnvm7 | (1 << 0));
+                       e1e_flush();
+               }
+       }
+
+       switch (hw->mac.type) {
+       case e1000_pch2lan:
+       case e1000_pch_lpt:
+               /* On I217, the clock frequency is 25MHz or 96MHz as
+                * indicated by the System Clock Frequency Indication
+                */
+               if ((hw->mac.type != e1000_pch_lpt) ||
+                   (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
+                       /* Stable 96MHz frequency */
+                       incperiod = INCPERIOD_96MHz;
+                       incvalue = INCVALUE_96MHz;
+                       shift = INCVALUE_SHIFT_96MHz;
+                       adapter->cc.shift = shift + INCPERIOD_SHIFT_96MHz;
+                       break;
+               }
+               /* fall-through */
+       case e1000_82574:
+       case e1000_82583:
+               /* Stable 25MHz frequency */
+               incperiod = INCPERIOD_25MHz;
+               incvalue = INCVALUE_25MHz;
+               shift = INCVALUE_SHIFT_25MHz;
+               adapter->cc.shift = shift;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       *timinca = ((incperiod << E1000_TIMINCA_INCPERIOD_SHIFT) |
+                   ((incvalue << shift) & E1000_TIMINCA_INCVALUE_MASK));
+
+       return 0;
+}
+
+/**
+ * e1000e_config_hwtstamp - configure the hwtstamp registers and enable/disable
+ * @adapter: board private structure
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't cause any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware filters.
+ * Not all combinations are supported, in particular event type has to be
+ * specified. Matching the kind of event packet is not supported, with the
+ * exception of "all V2 events regardless of level 2 or 4".
+ **/
+static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct hwtstamp_config *config = &adapter->hwtstamp_config;
+       u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
+       u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
+       u32 rxmtrl = 0;
+       u16 rxudp = 0;
+       bool is_l4 = false;
+       bool is_l2 = false;
+       u32 regval;
+       s32 ret_val;
+
+       if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+               return -EINVAL;
+
+       /* flags reserved for future extensions - must be zero */
+       if (config->flags)
+               return -EINVAL;
+
+       switch (config->tx_type) {
+       case HWTSTAMP_TX_OFF:
+               tsync_tx_ctl = 0;
+               break;
+       case HWTSTAMP_TX_ON:
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (config->rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               tsync_rx_ctl = 0;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+               rxmtrl = E1000_RXMTRL_PTP_V1_SYNC_MESSAGE;
+               is_l4 = true;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+               rxmtrl = E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE;
+               is_l4 = true;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+               /* Also time stamps V2 L2 Path Delay Request/Response */
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
+               rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
+               is_l2 = true;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+               /* Also time stamps V2 L2 Path Delay Request/Response. */
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
+               rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
+               is_l2 = true;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+               /* Hardware cannot filter just V2 L4 Sync messages;
+                * fall-through to V2 (both L2 and L4) Sync.
+                */
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+               /* Also time stamps V2 Path Delay Request/Response. */
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+               rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
+               is_l2 = true;
+               is_l4 = true;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+               /* Hardware cannot filter just V2 L4 Delay Request messages;
+                * fall-through to V2 (both L2 and L4) Delay Request.
+                */
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               /* Also time stamps V2 Path Delay Request/Response. */
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+               rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
+               is_l2 = true;
+               is_l4 = true;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+               /* Hardware cannot filter just V2 L4 or L2 Event messages;
+                * fall-through to all V2 (both L2 and L4) Events.
+                */
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
+               config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+               is_l2 = true;
+               is_l4 = true;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+               /* For V1, the hardware can only filter Sync messages or
+                * Delay Request messages but not both so fall-through to
+                * time stamp all packets.
+                */
+       case HWTSTAMP_FILTER_ALL:
+               is_l2 = true;
+               is_l4 = true;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
+               config->rx_filter = HWTSTAMP_FILTER_ALL;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       /* enable/disable Tx h/w time stamping */
+       regval = er32(TSYNCTXCTL);
+       regval &= ~E1000_TSYNCTXCTL_ENABLED;
+       regval |= tsync_tx_ctl;
+       ew32(TSYNCTXCTL, regval);
+       if ((er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_ENABLED) !=
+           (regval & E1000_TSYNCTXCTL_ENABLED)) {
+               e_err("Timesync Tx Control register not set as expected\n");
+               return -EAGAIN;
+       }
+
+       /* enable/disable Rx h/w time stamping */
+       regval = er32(TSYNCRXCTL);
+       regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
+       regval |= tsync_rx_ctl;
+       ew32(TSYNCRXCTL, regval);
+       if ((er32(TSYNCRXCTL) & (E1000_TSYNCRXCTL_ENABLED |
+                                E1000_TSYNCRXCTL_TYPE_MASK)) !=
+           (regval & (E1000_TSYNCRXCTL_ENABLED |
+                      E1000_TSYNCRXCTL_TYPE_MASK))) {
+               e_err("Timesync Rx Control register not set as expected\n");
+               return -EAGAIN;
+       }
+
+       /* L2: define ethertype filter for time stamped packets */
+       if (is_l2)
+               rxmtrl |= ETH_P_1588;
+
+       /* define which PTP packets get time stamped */
+       ew32(RXMTRL, rxmtrl);
+
+       /* Filter by destination port */
+       if (is_l4) {
+               rxudp = PTP_EV_PORT;
+               cpu_to_be16s(&rxudp);
+       }
+       ew32(RXUDP, rxudp);
+
+       e1e_flush();
+
+       /* Clear TSYNCRXCTL_VALID & TSYNCTXCTL_VALID bit */
+       er32(RXSTMPH);
+       er32(TXSTMPH);
+
+       /* Get and set the System Time Register SYSTIM base frequency */
+       ret_val = e1000e_get_base_timinca(adapter, &regval);
+       if (ret_val)
+               return ret_val;
+       ew32(TIMINCA, regval);
+
+       /* reset the ns time counter */
+       timecounter_init(&adapter->tc, &adapter->cc,
+                        ktime_to_ns(ktime_get_real()));
+
+       return 0;
+}
+
 /**
  * e1000_configure - configure the hardware for Rx and Tx
  * @adapter: private board structure
@@ -3473,14 +3847,17 @@ void e1000e_reset(struct e1000_adapter *adapter)
                break;
        case e1000_pch2lan:
        case e1000_pch_lpt:
-               fc->high_water = 0x05C20;
-               fc->low_water = 0x05048;
-               fc->pause_time = 0x0650;
                fc->refresh_time = 0x0400;
-               if (adapter->netdev->mtu > ETH_DATA_LEN) {
-                       pba = 14;
-                       ew32(PBA, pba);
+
+               if (adapter->netdev->mtu <= ETH_DATA_LEN) {
+                       fc->high_water = 0x05C20;
+                       fc->low_water = 0x05048;
+                       fc->pause_time = 0x0650;
+                       break;
                }
+
+               fc->high_water = ((pba << 10) * 9 / 10) & E1000_FCRTH_RTH;
+               fc->low_water = ((pba << 10) * 8 / 10) & E1000_FCRTL_RTL;
                break;
        }
 
@@ -3533,6 +3910,9 @@ void e1000e_reset(struct e1000_adapter *adapter)
 
        e1000e_reset_adaptive(hw);
 
+       /* initialize systim and reset the ns time counter */
+       e1000e_config_hwtstamp(adapter);
+
        if (!netif_running(adapter->netdev) &&
            !test_bit(__E1000_TESTING, &adapter->state)) {
                e1000_power_down_phy(adapter);
@@ -3668,6 +4048,24 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)
        clear_bit(__E1000_RESETTING, &adapter->state);
 }
 
+/**
+ * e1000e_cyclecounter_read - read raw cycle counter (used by time counter)
+ * @cc: cyclecounter structure
+ **/
+static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc)
+{
+       struct e1000_adapter *adapter = container_of(cc, struct e1000_adapter,
+                                                    cc);
+       struct e1000_hw *hw = &adapter->hw;
+       cycle_t systim;
+
+       /* latch SYSTIMH on read of SYSTIML */
+       systim = (cycle_t)er32(SYSTIML);
+       systim |= (cycle_t)er32(SYSTIMH) << 32;
+
+       return systim;
+}
+
 /**
  * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
  * @adapter: board private structure to initialize
@@ -3694,6 +4092,17 @@ static int e1000_sw_init(struct e1000_adapter *adapter)
        if (e1000_alloc_queues(adapter))
                return -ENOMEM;
 
+       /* Setup hardware time stamping cyclecounter */
+       if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
+               adapter->cc.read = e1000e_cyclecounter_read;
+               adapter->cc.mask = CLOCKSOURCE_MASK(64);
+               adapter->cc.mult = 1;
+               /* cc.shift set in e1000e_get_base_tininca() */
+
+               spin_lock_init(&adapter->systim_lock);
+               INIT_WORK(&adapter->tx_hwtstamp_work, e1000e_tx_hwtstamp_work);
+       }
+
        /* Explicitly disable IRQ since the NIC can be in any state. */
        e1000_irq_disable(adapter);
 
@@ -3877,10 +4286,8 @@ static int e1000_open(struct net_device *netdev)
                e1000_update_mng_vlan(adapter);
 
        /* DMA latency requirement to workaround jumbo issue */
-       if (adapter->hw.mac.type == e1000_pch2lan)
-               pm_qos_add_request(&adapter->netdev->pm_qos_req,
-                                  PM_QOS_CPU_DMA_LATENCY,
-                                  PM_QOS_DEFAULT_VALUE);
+       pm_qos_add_request(&adapter->netdev->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+                          PM_QOS_DEFAULT_VALUE);
 
        /* before we allocate an interrupt, we must be ready to handle it.
         * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -3988,8 +4395,7 @@ static int e1000_close(struct net_device *netdev)
            !test_bit(__E1000_TESTING, &adapter->state))
                e1000e_release_hw_control(adapter);
 
-       if (adapter->hw.mac.type == e1000_pch2lan)
-               pm_qos_remove_request(&adapter->netdev->pm_qos_req);
+       pm_qos_remove_request(&adapter->netdev->pm_qos_req);
 
        pm_runtime_put_sync(&pdev->dev);
 
@@ -4251,6 +4657,16 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
        adapter->stats.mgptc += er32(MGTPTC);
        adapter->stats.mgprc += er32(MGTPRC);
        adapter->stats.mgpdc += er32(MGTPDC);
+
+       /* Correctable ECC Errors */
+       if (hw->mac.type == e1000_pch_lpt) {
+               u32 pbeccsts = er32(PBECCSTS);
+               adapter->corr_errors +=
+                   pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+               adapter->uncorr_errors +=
+                   (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+                   E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+       }
 }
 
 /**
@@ -4300,9 +4716,8 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
        u32 ctrl = er32(CTRL);
 
        /* Link status message must follow this format for user tools */
-       printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
-               adapter->netdev->name,
-               adapter->link_speed,
+       pr_info("%s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
+               adapter->netdev->name, adapter->link_speed,
                adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half",
                (ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE) ? "Rx/Tx" :
                (ctrl & E1000_CTRL_RFCE) ? "Rx" :
@@ -4355,11 +4770,11 @@ static void e1000e_enable_receives(struct e1000_adapter *adapter)
 {
        /* make sure the receive unit is started */
        if ((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
-           (adapter->flags & FLAG_RX_RESTART_NOW)) {
+           (adapter->flags & FLAG_RESTART_NOW)) {
                struct e1000_hw *hw = &adapter->hw;
                u32 rctl = er32(RCTL);
                ew32(RCTL, rctl | E1000_RCTL_EN);
-               adapter->flags &= ~FLAG_RX_RESTART_NOW;
+               adapter->flags &= ~FLAG_RESTART_NOW;
        }
 }
 
@@ -4521,15 +4936,22 @@ static void e1000_watchdog_task(struct work_struct *work)
                        adapter->link_speed = 0;
                        adapter->link_duplex = 0;
                        /* Link status message must follow this format */
-                       printk(KERN_INFO "e1000e: %s NIC Link is Down\n",
-                              adapter->netdev->name);
+                       pr_info("%s NIC Link is Down\n", adapter->netdev->name);
                        netif_carrier_off(netdev);
                        if (!test_bit(__E1000_DOWN, &adapter->state))
                                mod_timer(&adapter->phy_info_timer,
                                          round_jiffies(jiffies + 2 * HZ));
 
-                       if (adapter->flags & FLAG_RX_NEEDS_RESTART)
-                               schedule_work(&adapter->reset_task);
+                       /* The link is lost so the controller stops DMA.
+                        * If there is queued Tx work that cannot be done
+                        * or if on an 8000ES2LAN which requires a Rx packet
+                        * buffer work-around on link down event, reset the
+                        * controller to flush the Tx/Rx packet buffers.
+                        * (Do the reset outside of interrupt context).
+                        */
+                       if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
+                           (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+                               adapter->flags |= FLAG_RESTART_NOW;
                        else
                                pm_schedule_suspend(netdev->dev.parent,
                                                        LINK_TIMEOUT);
@@ -4551,20 +4973,14 @@ link_up:
        adapter->gotc_old = adapter->stats.gotc;
        spin_unlock(&adapter->stats64_lock);
 
-       e1000e_update_adaptive(&adapter->hw);
-
-       if (!netif_carrier_ok(netdev) &&
-           (e1000_desc_unused(tx_ring) + 1 < tx_ring->count)) {
-               /* We've lost link, so the controller stops DMA,
-                * but we've got queued Tx work that's never going
-                * to get done, so reset controller to flush Tx.
-                * (Do the reset outside of interrupt context).
-                */
+       if (adapter->flags & FLAG_RESTART_NOW) {
                schedule_work(&adapter->reset_task);
                /* return immediately since reset is imminent */
                return;
        }
 
+       e1000e_update_adaptive(&adapter->hw);
+
        /* Simple mode for Interrupt Throttle Rate (ITR) */
        if (adapter->itr_setting == 4) {
                /* Symmetric Tx/Rx gets a reduced ITR=2000;
@@ -4601,6 +5017,17 @@ link_up:
        if (adapter->flags2 & FLAG2_CHECK_PHY_HANG)
                e1000e_check_82574_phy_workaround(adapter);
 
+       /* Clear valid timestamp stuck in RXSTMPL/H due to a Rx error */
+       if (adapter->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) {
+               if ((adapter->flags2 & FLAG2_CHECK_RX_HWTSTAMP) &&
+                   (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) {
+                       er32(RXSTMPH);
+                       adapter->rx_hwtstamp_cleared++;
+               } else {
+                       adapter->flags2 |= FLAG2_CHECK_RX_HWTSTAMP;
+               }
+       }
+
        /* Reset the timer */
        if (!test_bit(__E1000_DOWN, &adapter->state))
                mod_timer(&adapter->watchdog_timer,
@@ -4612,6 +5039,7 @@ link_up:
 #define E1000_TX_FLAGS_TSO             0x00000004
 #define E1000_TX_FLAGS_IPV4            0x00000008
 #define E1000_TX_FLAGS_NO_FCS          0x00000010
+#define E1000_TX_FLAGS_HWTSTAMP                0x00000020
 #define E1000_TX_FLAGS_VLAN_MASK       0xffff0000
 #define E1000_TX_FLAGS_VLAN_SHIFT      16
 
@@ -4870,6 +5298,11 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count)
        if (unlikely(tx_flags & E1000_TX_FLAGS_NO_FCS))
                txd_lower &= ~(E1000_TXD_CMD_IFCS);
 
+       if (unlikely(tx_flags & E1000_TX_FLAGS_HWTSTAMP)) {
+               txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+               txd_upper |= E1000_TXD_EXTCMD_TSTAMP;
+       }
+
        i = tx_ring->next_to_use;
 
        do {
@@ -4918,12 +5351,11 @@ static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
        struct e1000_hw *hw =  &adapter->hw;
        u16 length, offset;
 
-       if (vlan_tx_tag_present(skb)) {
-               if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
-                   (adapter->hw.mng_cookie.status &
-                       E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
-                       return 0;
-       }
+       if (vlan_tx_tag_present(skb) &&
+           !((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
+             (adapter->hw.mng_cookie.status &
+              E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
+               return 0;
 
        if (skb->len <= MINIMUM_DHCP_PACKET_SIZE)
                return 0;
@@ -5094,7 +5526,15 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
        count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit,
                             nr_frags);
        if (count) {
-               skb_tx_timestamp(skb);
+               if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+                            !adapter->tx_hwtstamp_skb)) {
+                       skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+                       tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
+                       adapter->tx_hwtstamp_skb = skb_get(skb);
+                       schedule_work(&adapter->tx_hwtstamp_work);
+               } else {
+                       skb_tx_timestamp(skb);
+               }
 
                netdev_sent_queue(netdev, skb->len);
                e1000_tx_queue(tx_ring, tx_flags, count);
@@ -5134,10 +5574,9 @@ static void e1000_reset_task(struct work_struct *work)
        if (test_bit(__E1000_DOWN, &adapter->state))
                return;
 
-       if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
-             (adapter->flags & FLAG_RX_RESTART_NOW))) {
+       if (!(adapter->flags & FLAG_RESTART_NOW)) {
                e1000e_dump(adapter);
-               e_err("Reset adapter\n");
+               e_err("Reset adapter unexpectedly\n");
        }
        e1000e_reinit_locked(adapter);
 }
@@ -5323,6 +5762,61 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
        return 0;
 }
 
+/**
+ * e1000e_hwtstamp_ioctl - control hardware time stamping
+ * @netdev: network interface device structure
+ * @ifreq: interface request
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't cause any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware filters.
+ * Not all combinations are supported, in particular event type has to be
+ * specified. Matching the kind of event packet is not supported, with the
+ * exception of "all V2 events regardless of level 2 or 4".
+ **/
+static int e1000e_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct hwtstamp_config config;
+       int ret_val;
+
+       if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+               return -EFAULT;
+
+       adapter->hwtstamp_config = config;
+
+       ret_val = e1000e_config_hwtstamp(adapter);
+       if (ret_val)
+               return ret_val;
+
+       config = adapter->hwtstamp_config;
+
+       switch (config.rx_filter) {
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               /* With V2 type filters which specify a Sync or Delay Request,
+                * Path Delay Request/Response messages are also time stamped
+                * by hardware so notify the caller the requested packets plus
+                * some others are time stamped.
+                */
+               config.rx_filter = HWTSTAMP_FILTER_SOME;
+               break;
+       default:
+               break;
+       }
+
+       return copy_to_user(ifr->ifr_data, &config,
+                           sizeof(config)) ? -EFAULT : 0;
+}
+
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
        switch (cmd) {
@@ -5330,6 +5824,8 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
        case SIOCGMIIREG:
        case SIOCSMIIREG:
                return e1000_mii_ioctl(netdev, ifr, cmd);
+       case SIOCSHWTSTAMP:
+               return e1000e_hwtstamp_ioctl(netdev, ifr);
        default:
                return -EOPNOTSUPP;
        }
@@ -5340,7 +5836,7 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
        struct e1000_hw *hw = &adapter->hw;
        u32 i, mac_reg;
        u16 phy_reg, wuc_enable;
-       int retval = 0;
+       int retval;
 
        /* copy MAC RARs to PHY RARs */
        e1000_copy_rx_addrs_to_phy_ich8lan(hw);
@@ -5554,14 +6050,21 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 #else
 static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 {
+       u16 aspm_ctl = 0;
+
+       if (state & PCIE_LINK_STATE_L0S)
+               aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L0S;
+       if (state & PCIE_LINK_STATE_L1)
+               aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L1;
+
        /* Both device and parent should have the same ASPM setting.
         * Disable ASPM in downstream component first and then upstream.
         */
-       pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, state);
+       pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_ctl);
 
        if (pdev->bus->self)
                pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
-                                          state);
+                                          aspm_ctl);
 }
 #endif
 static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
@@ -6228,11 +6731,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                        "NVM Read Error while reading MAC address\n");
 
        memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
-       memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
-       if (!is_valid_ether_addr(netdev->perm_addr)) {
+       if (!is_valid_ether_addr(netdev->dev_addr)) {
                dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
-                       netdev->perm_addr);
+                       netdev->dev_addr);
                err = -EIO;
                goto err_eeprom;
        }
@@ -6318,6 +6820,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);
 
+       /* init PTP hardware clock */
+       e1000e_ptp_init(adapter);
+
        e1000_print_device_info(adapter);
 
        if (pci_dev_run_wake(pdev))
@@ -6366,6 +6871,8 @@ static void e1000_remove(struct pci_dev *pdev)
        struct e1000_adapter *adapter = netdev_priv(netdev);
        bool down = test_bit(__E1000_DOWN, &adapter->state);
 
+       e1000e_ptp_remove(adapter);
+
        /* The timers may be rescheduled, so explicitly disable them
         * from being rescheduled.
         */
@@ -6380,6 +6887,14 @@ static void e1000_remove(struct pci_dev *pdev)
        cancel_work_sync(&adapter->update_phy_task);
        cancel_work_sync(&adapter->print_hang_task);
 
+       if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
+               cancel_work_sync(&adapter->tx_hwtstamp_work);
+               if (adapter->tx_hwtstamp_skb) {
+                       dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+                       adapter->tx_hwtstamp_skb = NULL;
+               }
+       }
+
        if (!(netdev->flags & IFF_UP))
                e1000_power_down_phy(adapter);
 
@@ -6532,7 +7047,7 @@ static int __init e1000_init_module(void)
        int ret;
        pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
                e1000e_driver_version);
-       pr_info("Copyright(c) 1999 - 2012 Intel Corporation.\n");
+       pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n");
        ret = pci_register_driver(&e1000_driver);
 
        return ret;
index b6468804cb2e74e8e317622ae4f36067c8f8780e..84fecc268162417b676f65066abc2fb2e4bd20bf 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -359,7 +359,7 @@ s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 {
        struct e1000_nvm_info *nvm = &hw->nvm;
-       s32 ret_val;
+       s32 ret_val = -E1000_ERR_NVM;
        u16 widx = 0;
 
        /* A check for invalid values:  offset too large, too many words,
@@ -371,16 +371,18 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
                return -E1000_ERR_NVM;
        }
 
-       ret_val = nvm->ops.acquire(hw);
-       if (ret_val)
-               return ret_val;
-
        while (widx < words) {
                u8 write_opcode = NVM_WRITE_OPCODE_SPI;
 
-               ret_val = e1000_ready_nvm_eeprom(hw);
+               ret_val = nvm->ops.acquire(hw);
                if (ret_val)
-                       goto release;
+                       return ret_val;
+
+               ret_val = e1000_ready_nvm_eeprom(hw);
+               if (ret_val) {
+                       nvm->ops.release(hw);
+                       return ret_val;
+               }
 
                e1000_standby_nvm(hw);
 
@@ -413,12 +415,10 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
                                break;
                        }
                }
+               usleep_range(10000, 20000);
+               nvm->ops.release(hw);
        }
 
-       usleep_range(10000, 20000);
-release:
-       nvm->ops.release(hw);
-
        return ret_val;
 }
 
@@ -464,8 +464,8 @@ s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
        if (nvm_data != NVM_PBA_PTR_GUARD) {
                e_dbg("NVM PBA number is not stored as string\n");
 
-               /* we will need 11 characters to store the PBA */
-               if (pba_num_size < 11) {
+               /* make sure callers buffer is big enough to store the PBA */
+               if (pba_num_size < E1000_PBANUM_LENGTH) {
                        e_dbg("PBA string buffer too small\n");
                        return E1000_ERR_NO_SPACE;
                }
index 89d536dd7ff51e3cbcd688f682cd00a84e000ce7..19c40d6f53ccb8f2c09bc3918e3917105e9deb74 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -447,8 +447,7 @@ void e1000e_check_options(struct e1000_adapter *adapter)
                if (num_SmartPowerDownEnable > bd) {
                        unsigned int spd = SmartPowerDownEnable[bd];
                        e1000_validate_option(&spd, &opt, adapter);
-                       if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN)
-                           && spd)
+                       if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && spd)
                                adapter->flags |= FLAG_SMART_POWER_DOWN;
                }
        }
index 28b38ff37e843a028f89d7fab86827a777e5a098..cddfc6b92f750c82054f05b354da22f3b5835a34 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 
 #include "e1000.h"
 
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
 static s32 e1000_wait_autoneg(struct e1000_hw *hw);
-static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg);
 static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
                                          u16 *data, bool read, bool page_set);
 static u32 e1000_get_phy_addr_for_hv_page(u32 page);
 static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
-                                          u16 *data, bool read);
+                                         u16 *data, bool read);
 
 /* Cable length tables */
 static const u16 e1000_m88_cable_length_table[] = {
@@ -792,7 +788,7 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
                        if (ret_val)
                                return ret_val;
                        /* Commit the changes. */
-                       ret_val = e1000e_commit_phy(hw);
+                       ret_val = phy->ops.commit(hw);
                        if (ret_val) {
                                e_dbg("Error committing the PHY changes\n");
                                return ret_val;
@@ -848,10 +844,12 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
        }
 
        /* Commit the changes. */
-       ret_val = e1000e_commit_phy(hw);
-       if (ret_val) {
-               e_dbg("Error committing the PHY changes\n");
-               return ret_val;
+       if (phy->ops.commit) {
+               ret_val = phy->ops.commit(hw);
+               if (ret_val) {
+                       e_dbg("Error committing the PHY changes\n");
+                       return ret_val;
+               }
        }
 
        if (phy->type == e1000_phy_82578) {
@@ -895,10 +893,12 @@ s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
        msleep(100);
 
        /* disable lplu d0 during driver init */
-       ret_val = e1000_set_d0_lplu_state(hw, false);
-       if (ret_val) {
-               e_dbg("Error Disabling LPLU D0\n");
-               return ret_val;
+       if (hw->phy.ops.set_d0_lplu_state) {
+               ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+               if (ret_val) {
+                       e_dbg("Error Disabling LPLU D0\n");
+                       return ret_val;
+               }
        }
        /* Configure mdi-mdix settings */
        ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
@@ -1196,7 +1196,7 @@ s32 e1000e_setup_copper_link(struct e1000_hw *hw)
                 * depending on user settings.
                 */
                e_dbg("Forcing Speed and Duplex\n");
-               ret_val = e1000_phy_force_speed_duplex(hw);
+               ret_val = hw->phy.ops.force_speed_duplex(hw);
                if (ret_val) {
                        e_dbg("Error Forcing Speed and Duplex\n");
                        return ret_val;
@@ -1326,9 +1326,11 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
                return ret_val;
 
        /* Reset the phy to commit changes. */
-       ret_val = e1000e_commit_phy(hw);
-       if (ret_val)
-               return ret_val;
+       if (hw->phy.ops.commit) {
+               ret_val = hw->phy.ops.commit(hw);
+               if (ret_val)
+                       return ret_val;
+       }
 
        if (phy->autoneg_wait_to_complete) {
                e_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
@@ -1962,7 +1964,7 @@ s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
        phy->is_mdix = !!(phy_data & M88E1000_PSSR_MDIX);
 
        if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
-               ret_val = e1000_get_cable_length(hw);
+               ret_val = hw->phy.ops.get_cable_length(hw);
                if (ret_val)
                        return ret_val;
 
@@ -2026,7 +2028,7 @@ s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
 
        if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
            IGP01E1000_PSSR_SPEED_1000MBPS) {
-               ret_val = e1000_get_cable_length(hw);
+               ret_val = phy->ops.get_cable_length(hw);
                if (ret_val)
                        return ret_val;
 
@@ -2166,17 +2168,17 @@ s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
 
        phy->ops.release(hw);
 
-       return e1000_get_phy_cfg_done(hw);
+       return phy->ops.get_cfg_done(hw);
 }
 
 /**
- *  e1000e_get_cfg_done - Generic configuration done
+ *  e1000e_get_cfg_done_generic - Generic configuration done
  *  @hw: pointer to the HW structure
  *
  *  Generic function to wait 10 milli-seconds for configuration to complete
  *  and return success.
  **/
-s32 e1000e_get_cfg_done(struct e1000_hw *hw)
+s32 e1000e_get_cfg_done_generic(struct e1000_hw *hw)
 {
        mdelay(10);
 
@@ -2266,38 +2268,6 @@ s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw)
        return 0;
 }
 
-/* Internal function pointers */
-
-/**
- *  e1000_get_phy_cfg_done - Generic PHY configuration done
- *  @hw: pointer to the HW structure
- *
- *  Return success if silicon family did not implement a family specific
- *  get_cfg_done function.
- **/
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
-{
-       if (hw->phy.ops.get_cfg_done)
-               return hw->phy.ops.get_cfg_done(hw);
-
-       return 0;
-}
-
-/**
- *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
- *  @hw: pointer to the HW structure
- *
- *  When the silicon family has not implemented a forced speed/duplex
- *  function for the PHY, simply return 0.
- **/
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
-{
-       if (hw->phy.ops.force_speed_duplex)
-               return hw->phy.ops.force_speed_duplex(hw);
-
-       return 0;
-}
-
 /**
  *  e1000e_get_phy_type_from_id - Get PHY type from id
  *  @phy_id: phy_id read from the phy
@@ -2672,7 +2642,7 @@ s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
  **/
 s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
 {
-       s32 ret_val = 0;
+       s32 ret_val;
 
        /* Select Port Control Registers page */
        ret_val = e1000_set_page_igp(hw, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
@@ -2805,43 +2775,6 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw)
        usleep_range(1000, 2000);
 }
 
-/**
- *  e1000e_commit_phy - Soft PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Performs a soft PHY reset on those that apply. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 e1000e_commit_phy(struct e1000_hw *hw)
-{
-       if (hw->phy.ops.commit)
-               return hw->phy.ops.commit(hw);
-
-       return 0;
-}
-
-/**
- *  e1000_set_d0_lplu_state - Sets low power link up state for D0
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D0
- *  and SmartSpeed is disabled when active is true, else clear lplu for D0
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.  This is a function pointer entry point called by drivers.
- **/
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
-{
-       if (hw->phy.ops.set_d0_lplu_state)
-               return hw->phy.ops.set_d0_lplu_state(hw, active);
-
-       return 0;
-}
-
 /**
  *  __e1000_read_phy_reg_hv -  Read HV PHY register
  *  @hw: pointer to the HW structure
@@ -3104,8 +3037,8 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
                                           u16 *data, bool read)
 {
        s32 ret_val;
-       u32 addr_reg = 0;
-       u32 data_reg = 0;
+       u32 addr_reg;
+       u32 data_reg;
 
        /* This takes care of the difference with desktop vs mobile phy */
        addr_reg = (hw->phy.type == e1000_phy_82578) ?
@@ -3333,7 +3266,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
                 I82577_DSTATUS_CABLE_LENGTH_SHIFT;
 
        if (length == E1000_CABLE_LENGTH_UNDEFINED)
-               ret_val = -E1000_ERR_PHY;
+               return -E1000_ERR_PHY;
 
        phy->cable_length = length;
 
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
new file mode 100644 (file)
index 0000000..6b8df65
--- /dev/null
@@ -0,0 +1,276 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* PTP 1588 Hardware Clock (PHC)
+ * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb)
+ * Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
+ */
+
+#include "e1000.h"
+
+/**
+ * e1000e_phc_adjfreq - adjust the frequency of the hardware clock
+ * @ptp: ptp clock structure
+ * @delta: Desired frequency change in parts per billion
+ *
+ * Adjust the frequency of the PHC cycle counter by the indicated delta from
+ * the base frequency.
+ **/
+static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
+{
+       struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+                                                    ptp_clock_info);
+       struct e1000_hw *hw = &adapter->hw;
+       bool neg_adj = false;
+       u64 adjustment;
+       u32 timinca, incvalue;
+       s32 ret_val;
+
+       if ((delta > ptp->max_adj) || (delta <= -1000000000))
+               return -EINVAL;
+
+       if (delta < 0) {
+               neg_adj = true;
+               delta = -delta;
+       }
+
+       /* Get the System Time Register SYSTIM base frequency */
+       ret_val = e1000e_get_base_timinca(adapter, &timinca);
+       if (ret_val)
+               return ret_val;
+
+       incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
+
+       adjustment = incvalue;
+       adjustment *= delta;
+       adjustment = div_u64(adjustment, 1000000000);
+
+       incvalue = neg_adj ? (incvalue - adjustment) : (incvalue + adjustment);
+
+       timinca &= ~E1000_TIMINCA_INCVALUE_MASK;
+       timinca |= incvalue;
+
+       ew32(TIMINCA, timinca);
+
+       return 0;
+}
+
+/**
+ * e1000e_phc_adjtime - Shift the time of the hardware clock
+ * @ptp: ptp clock structure
+ * @delta: Desired change in nanoseconds
+ *
+ * Adjust the timer by resetting the timecounter structure.
+ **/
+static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+                                                    ptp_clock_info);
+       unsigned long flags;
+       s64 now;
+
+       spin_lock_irqsave(&adapter->systim_lock, flags);
+       now = timecounter_read(&adapter->tc);
+       now += delta;
+       timecounter_init(&adapter->tc, &adapter->cc, now);
+       spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+       return 0;
+}
+
+/**
+ * e1000e_phc_gettime - Reads the current time from the hardware clock
+ * @ptp: ptp clock structure
+ * @ts: timespec structure to hold the current time value
+ *
+ * Read the timecounter and return the correct value in ns after converting
+ * it into a struct timespec.
+ **/
+static int e1000e_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+                                                    ptp_clock_info);
+       unsigned long flags;
+       u32 remainder;
+       u64 ns;
+
+       spin_lock_irqsave(&adapter->systim_lock, flags);
+       ns = timecounter_read(&adapter->tc);
+       spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+       ts->tv_sec = div_u64_rem(ns, NSEC_PER_SEC, &remainder);
+       ts->tv_nsec = remainder;
+
+       return 0;
+}
+
+/**
+ * e1000e_phc_settime - Set the current time on the hardware clock
+ * @ptp: ptp clock structure
+ * @ts: timespec containing the new time for the cycle counter
+ *
+ * Reset the timecounter to use a new base value instead of the kernel
+ * wall timer value.
+ **/
+static int e1000e_phc_settime(struct ptp_clock_info *ptp,
+                             const struct timespec *ts)
+{
+       struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+                                                    ptp_clock_info);
+       unsigned long flags;
+       u64 ns;
+
+       ns = ts->tv_sec * NSEC_PER_SEC;
+       ns += ts->tv_nsec;
+
+       /* reset the timecounter */
+       spin_lock_irqsave(&adapter->systim_lock, flags);
+       timecounter_init(&adapter->tc, &adapter->cc, ns);
+       spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+       return 0;
+}
+
+/**
+ * e1000e_phc_enable - enable or disable an ancillary feature
+ * @ptp: ptp clock structure
+ * @request: Desired resource to enable or disable
+ * @on: Caller passes one to enable or zero to disable
+ *
+ * Enable (or disable) ancillary features of the PHC subsystem.
+ * Currently, no ancillary features are supported.
+ **/
+static int e1000e_phc_enable(struct ptp_clock_info *ptp,
+                            struct ptp_clock_request *request, int on)
+{
+       return -EOPNOTSUPP;
+}
+
+static void e1000e_systim_overflow_work(struct work_struct *work)
+{
+       struct e1000_adapter *adapter = container_of(work, struct e1000_adapter,
+                                                    systim_overflow_work.work);
+       struct e1000_hw *hw = &adapter->hw;
+       struct timespec ts;
+
+       adapter->ptp_clock_info.gettime(&adapter->ptp_clock_info, &ts);
+
+       e_dbg("SYSTIM overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
+
+       schedule_delayed_work(&adapter->systim_overflow_work,
+                             E1000_SYSTIM_OVERFLOW_PERIOD);
+}
+
+static const struct ptp_clock_info e1000e_ptp_clock_info = {
+       .owner          = THIS_MODULE,
+       .n_alarm        = 0,
+       .n_ext_ts       = 0,
+       .n_per_out      = 0,
+       .pps            = 0,
+       .adjfreq        = e1000e_phc_adjfreq,
+       .adjtime        = e1000e_phc_adjtime,
+       .gettime        = e1000e_phc_gettime,
+       .settime        = e1000e_phc_settime,
+       .enable         = e1000e_phc_enable,
+};
+
+/**
+ * e1000e_ptp_init - initialize PTP for devices which support it
+ * @adapter: board private structure
+ *
+ * This function performs the required steps for enabling PTP support.
+ * If PTP support has already been loaded it simply calls the cyclecounter
+ * init routine and exits.
+ **/
+void e1000e_ptp_init(struct e1000_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       adapter->ptp_clock = NULL;
+
+       if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+               return;
+
+       adapter->ptp_clock_info = e1000e_ptp_clock_info;
+
+       snprintf(adapter->ptp_clock_info.name,
+                sizeof(adapter->ptp_clock_info.name), "%pm",
+                adapter->netdev->perm_addr);
+
+       switch (hw->mac.type) {
+       case e1000_pch2lan:
+       case e1000_pch_lpt:
+               if ((hw->mac.type != e1000_pch_lpt) ||
+                   (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
+                       adapter->ptp_clock_info.max_adj = 24000000 - 1;
+                       break;
+               }
+               /* fall-through */
+       case e1000_82574:
+       case e1000_82583:
+               adapter->ptp_clock_info.max_adj = 600000000 - 1;
+               break;
+       default:
+               break;
+       }
+
+       INIT_DELAYED_WORK(&adapter->systim_overflow_work,
+                         e1000e_systim_overflow_work);
+
+       schedule_delayed_work(&adapter->systim_overflow_work,
+                             E1000_SYSTIM_OVERFLOW_PERIOD);
+
+       adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
+                                               &adapter->pdev->dev);
+       if (IS_ERR(adapter->ptp_clock)) {
+               adapter->ptp_clock = NULL;
+               e_err("ptp_clock_register failed\n");
+       } else {
+               e_info("registered PHC clock\n");
+       }
+}
+
+/**
+ * e1000e_ptp_remove - disable PTP device and stop the overflow check
+ * @adapter: board private structure
+ *
+ * Stop the PTP support, and cancel the delayed work.
+ **/
+void e1000e_ptp_remove(struct e1000_adapter *adapter)
+{
+       if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+               return;
+
+       cancel_delayed_work_sync(&adapter->systim_overflow_work);
+
+       if (adapter->ptp_clock) {
+               ptp_clock_unregister(adapter->ptp_clock);
+               adapter->ptp_clock = NULL;
+               e_info("removed PHC\n");
+       }
+}
index 624476cfa727cc32efc39a8846fb3720742077ed..f19700e285bb5f5397b3ace776453974f4e8a9d5 100644 (file)
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel 82575 PCI-Express Ethernet Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
@@ -34,4 +34,4 @@ obj-$(CONFIG_IGB) += igb.o
 
 igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
            e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
-           e1000_i210.o igb_ptp.o
+           e1000_i210.o igb_ptp.o igb_hwmon.o
index fdaaf2709d0ae660480e3c6525e116481a369c4c..54a7c20d9fa08ced8a2fa4effd84f5fdcaa82471 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -33,6 +33,7 @@
 
 #include <linux/types.h>
 #include <linux/if_ether.h>
+#include <linux/i2c.h>
 
 #include "e1000_mac.h"
 #include "e1000_82575.h"
@@ -2302,18 +2303,157 @@ out:
        return ret_val;
 }
 
+static const u8 e1000_emc_temp_data[4] = {
+       E1000_EMC_INTERNAL_DATA,
+       E1000_EMC_DIODE1_DATA,
+       E1000_EMC_DIODE2_DATA,
+       E1000_EMC_DIODE3_DATA
+};
+static const u8 e1000_emc_therm_limit[4] = {
+       E1000_EMC_INTERNAL_THERM_LIMIT,
+       E1000_EMC_DIODE1_THERM_LIMIT,
+       E1000_EMC_DIODE2_THERM_LIMIT,
+       E1000_EMC_DIODE3_THERM_LIMIT
+};
+
+/* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
+ *  @hw: pointer to hardware structure
+ *
+ *  Updates the temperatures in mac.thermal_sensor_data
+ */
+s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
+{
+       s32 status = E1000_SUCCESS;
+       u16 ets_offset;
+       u16 ets_cfg;
+       u16 ets_sensor;
+       u8  num_sensors;
+       u8  sensor_index;
+       u8  sensor_location;
+       u8  i;
+       struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+       if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
+               return E1000_NOT_IMPLEMENTED;
+
+       data->sensor[0].temp = (rd32(E1000_THMJT) & 0xFF);
+
+       /* Return the internal sensor only if ETS is unsupported */
+       hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
+       if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
+               return status;
+
+       hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
+       if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+           != NVM_ETS_TYPE_EMC)
+               return E1000_NOT_IMPLEMENTED;
+
+       num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
+       if (num_sensors > E1000_MAX_SENSORS)
+               num_sensors = E1000_MAX_SENSORS;
+
+       for (i = 1; i < num_sensors; i++) {
+               hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
+               sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
+                               NVM_ETS_DATA_INDEX_SHIFT);
+               sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
+                                  NVM_ETS_DATA_LOC_SHIFT);
+
+               if (sensor_location != 0)
+                       hw->phy.ops.read_i2c_byte(hw,
+                                       e1000_emc_temp_data[sensor_index],
+                                       E1000_I2C_THERMAL_SENSOR_ADDR,
+                                       &data->sensor[i].temp);
+       }
+       return status;
+}
+
+/* igb_init_thermal_sensor_thresh_generic - Sets thermal sensor thresholds
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the thermal sensor thresholds according to the NVM map
+ *  and save off the threshold and location values into mac.thermal_sensor_data
+ */
+s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
+{
+       s32 status = E1000_SUCCESS;
+       u16 ets_offset;
+       u16 ets_cfg;
+       u16 ets_sensor;
+       u8  low_thresh_delta;
+       u8  num_sensors;
+       u8  sensor_index;
+       u8  sensor_location;
+       u8  therm_limit;
+       u8  i;
+       struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+       if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
+               return E1000_NOT_IMPLEMENTED;
+
+       memset(data, 0, sizeof(struct e1000_thermal_sensor_data));
+
+       data->sensor[0].location = 0x1;
+       data->sensor[0].caution_thresh =
+               (rd32(E1000_THHIGHTC) & 0xFF);
+       data->sensor[0].max_op_thresh =
+               (rd32(E1000_THLOWTC) & 0xFF);
+
+       /* Return the internal sensor only if ETS is unsupported */
+       hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
+       if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
+               return status;
+
+       hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
+       if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+           != NVM_ETS_TYPE_EMC)
+               return E1000_NOT_IMPLEMENTED;
+
+       low_thresh_delta = ((ets_cfg & NVM_ETS_LTHRES_DELTA_MASK) >>
+                           NVM_ETS_LTHRES_DELTA_SHIFT);
+       num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
+
+       for (i = 1; i <= num_sensors; i++) {
+               hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
+               sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
+                               NVM_ETS_DATA_INDEX_SHIFT);
+               sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
+                                  NVM_ETS_DATA_LOC_SHIFT);
+               therm_limit = ets_sensor & NVM_ETS_DATA_HTHRESH_MASK;
+
+               hw->phy.ops.write_i2c_byte(hw,
+                       e1000_emc_therm_limit[sensor_index],
+                       E1000_I2C_THERMAL_SENSOR_ADDR,
+                       therm_limit);
+
+               if ((i < E1000_MAX_SENSORS) && (sensor_location != 0)) {
+                       data->sensor[i].location = sensor_location;
+                       data->sensor[i].caution_thresh = therm_limit;
+                       data->sensor[i].max_op_thresh = therm_limit -
+                                                       low_thresh_delta;
+               }
+       }
+       return status;
+}
+
 static struct e1000_mac_operations e1000_mac_ops_82575 = {
        .init_hw              = igb_init_hw_82575,
        .check_for_link       = igb_check_for_link_82575,
        .rar_set              = igb_rar_set,
        .read_mac_addr        = igb_read_mac_addr_82575,
        .get_speed_and_duplex = igb_get_speed_and_duplex_copper,
+#ifdef CONFIG_IGB_HWMON
+       .get_thermal_sensor_data = igb_get_thermal_sensor_data_generic,
+       .init_thermal_sensor_thresh = igb_init_thermal_sensor_thresh_generic,
+#endif
 };
 
 static struct e1000_phy_operations e1000_phy_ops_82575 = {
        .acquire              = igb_acquire_phy_82575,
        .get_cfg_done         = igb_get_cfg_done_82575,
        .release              = igb_release_phy_82575,
+       .write_i2c_byte       = igb_write_i2c_byte,
+       .read_i2c_byte        = igb_read_i2c_byte,
 };
 
 static struct e1000_nvm_operations e1000_nvm_ops_82575 = {
index 44b76b3b6816692f2bcea6682950791a92164bda..73ab41f0e032009422cf3488c851ea118cd0109c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -32,6 +32,10 @@ extern void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
 extern void igb_power_up_serdes_link_82575(struct e1000_hw *hw);
 extern void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
 extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
+extern s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+                               u8 dev_addr, u8 *data);
+extern s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+                                u8 dev_addr, u8 data);
 
 #define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
                                      (ID_LED_DEF1_DEF2 <<  8) | \
@@ -260,5 +264,16 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
 void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
 u16 igb_rxpbs_adjust_82580(u32 data);
 s32 igb_set_eee_i350(struct e1000_hw *);
-
+s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *);
+s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw);
+
+#define E1000_I2C_THERMAL_SENSOR_ADDR  0xF8
+#define E1000_EMC_INTERNAL_DATA                0x00
+#define E1000_EMC_INTERNAL_THERM_LIMIT 0x20
+#define E1000_EMC_DIODE1_DATA          0x01
+#define E1000_EMC_DIODE1_THERM_LIMIT   0x19
+#define E1000_EMC_DIODE2_DATA          0x23
+#define E1000_EMC_DIODE2_THERM_LIMIT   0x1A
+#define E1000_EMC_DIODE3_DATA          0x2A
+#define E1000_EMC_DIODE3_THERM_LIMIT   0x30
 #endif
index 45dce06eff264d77dd5d6b350ef2e3a1dd94447f..7e13337d3b9d519bb33b3df0f362d1d63f77cf69 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #define E1000_ERR_NO_SPACE          17
 #define E1000_ERR_NVM_PBA_SECTION   18
 #define E1000_ERR_INVM_VALUE_NOT_FOUND 19
+#define E1000_ERR_I2C               20
 
 /* Loop limit on how long we wait for auto-negotiation to complete */
 #define COPPER_LINK_UP_LIMIT              10
 #define NVM_COMB_VER_SHFT               8
 #define NVM_VER_INVALID            0xFFFF
 #define NVM_ETRACK_SHIFT               16
+#define NVM_ETS_CFG                    0x003E
+#define NVM_ETS_LTHRES_DELTA_MASK      0x07C0
+#define NVM_ETS_LTHRES_DELTA_SHIFT     6
+#define NVM_ETS_TYPE_MASK              0x0038
+#define NVM_ETS_TYPE_SHIFT             3
+#define NVM_ETS_TYPE_EMC               0x000
+#define NVM_ETS_NUM_SENSORS_MASK       0x0007
+#define NVM_ETS_DATA_LOC_MASK          0x3C00
+#define NVM_ETS_DATA_LOC_SHIFT         10
+#define NVM_ETS_DATA_INDEX_MASK                0x0300
+#define NVM_ETS_DATA_INDEX_SHIFT       8
+#define NVM_ETS_DATA_HTHRESH_MASK      0x00FF
 
 #define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
 #define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
index c2a51dcda550107e2b266dff9e1ba2f9b1cc83be..0d5cf9c63d0d1192930fdda4e5f12bf254dc3974 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -325,6 +325,10 @@ struct e1000_mac_operations {
        s32  (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
        s32  (*acquire_swfw_sync)(struct e1000_hw *, u16);
        void (*release_swfw_sync)(struct e1000_hw *, u16);
+#ifdef CONFIG_IGB_HWMON
+       s32 (*get_thermal_sensor_data)(struct e1000_hw *);
+       s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
+#endif
 
 };
 
@@ -342,6 +346,8 @@ struct e1000_phy_operations {
        s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
        s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
        s32  (*write_reg)(struct e1000_hw *, u32, u16);
+       s32 (*read_i2c_byte)(struct e1000_hw *, u8, u8, u8 *);
+       s32 (*write_i2c_byte)(struct e1000_hw *, u8, u8, u8);
 };
 
 struct e1000_nvm_operations {
@@ -354,6 +360,19 @@ struct e1000_nvm_operations {
        s32  (*valid_led_default)(struct e1000_hw *, u16 *);
 };
 
+#define E1000_MAX_SENSORS              3
+
+struct e1000_thermal_diode_data {
+       u8 location;
+       u8 temp;
+       u8 caution_thresh;
+       u8 max_op_thresh;
+};
+
+struct e1000_thermal_sensor_data {
+       struct e1000_thermal_diode_data sensor[E1000_MAX_SENSORS];
+};
+
 struct e1000_info {
        s32 (*get_invariants)(struct e1000_hw *);
        struct e1000_mac_operations *mac_ops;
@@ -399,6 +418,7 @@ struct e1000_mac_info {
        bool report_tx_early;
        bool serdes_has_link;
        bool tx_pkt_filtering;
+       struct e1000_thermal_sensor_data thermal_sensor_data;
 };
 
 struct e1000_phy_info {
index fbcdbebb0b5fce2c4108a130e24d490cbada6cf7..6a42344f24f1805ed6b3e2fe1c4afa98cb1534cf 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index 1c89358a99ab84b384f4d6819dd550aa7cc2a34d..e4e1a73b7c75a145a17641f3302355107e8b4f4c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index 101e6e4da97fb5287852d555409618c7cf7bf854..a5c7200b9a71b8637a31de1c74fcfa6eb48018d3 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index e2b2c4b9c951fd704a5d452f00e6efd190ec307b..e6d6ce433261f8be8a125e00ee9fdf1bb114e606 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index 5988b8958baff22cfb0f2de6f71eae4fc578681a..38e0df35090422609b50d00b5834bb4b2a377916 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index dbcfa3d5caeca753cf22a4f37e9cb313d9c30fa7..c13b56d9edb25e8436e8ffbad9c74e8cdcd36e0b 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index fbb7604db364f59729bb3f6c36d41758d4cf40ba..5b62adbe134de0f9bba71e23b25c01aa95e054b8 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index 7012d458c6f7eff8df5ae1c0e25cd4a5abaa486d..6bfc0c43aace635084b265441c1fb91cb6c86bdc 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2012 Intel Corporation.
+  Copyright(c) 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index fe76004aca4e7a8464811629d9cfec18dac2f8b2..2918c979b5bba54a74a5d3844ee265aaacf62680 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index ed282f877d9a0b08df7b7a2673d0e3d0d67c5216..784fd1c40989fc86bbdb5d750bc61f5cd40da187 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index e5db48594e8a929daab778dca1fe7c9b92f0e7fa..15343286082e009acc711eecc4d2555875dd807d 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
 #define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
 #define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+#define E1000_I2CPARAMS        0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_I2CBB_EN      0x00000100  /* I2C - Bit Bang Enable */
+#define E1000_I2C_CLK_OUT   0x00000200  /* I2C- Clock */
+#define E1000_I2C_DATA_OUT  0x00000400  /* I2C- Data Out */
+#define E1000_I2C_DATA_OE_N 0x00000800  /* I2C- Data Output Enable */
+#define E1000_I2C_DATA_IN   0x00001000  /* I2C- Data In */
+#define E1000_I2C_CLK_OE_N  0x00002000  /* I2C- Clock Output Enable */
+#define E1000_I2C_CLK_IN    0x00004000  /* I2C- Clock In */
 
 /* IEEE 1588 TIMESYNCH */
 #define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
 
 /* Split and Replication RX Control - RW */
 #define E1000_RXPBS    0x02404  /* Rx Packet Buffer Size - RW */
+
+/* Thermal sensor configuration and status registers */
+#define E1000_THMJT    0x08100 /* Junction Temperature */
+#define E1000_THLOWTC  0x08104 /* Low Threshold Control */
+#define E1000_THMIDTC  0x08108 /* Mid Threshold Control */
+#define E1000_THHIGHTC 0x0810C /* High Threshold Control */
+#define E1000_THSTAT   0x08110 /* Thermal Sensor Status */
+
 /*
  * Convenience macros
  *
index 17f1686ee411fe3e63aea5fdcfacaa1abe6e8ee1..4b78053592baf8650d89a987348138999d73fcab 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -39,6 +39,8 @@
 #include <linux/ptp_clock_kernel.h>
 #include <linux/bitops.h>
 #include <linux/if_vlan.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 
 struct igb_adapter;
 
@@ -219,6 +221,7 @@ struct igb_ring {
                struct igb_tx_buffer *tx_buffer_info;
                struct igb_rx_buffer *rx_buffer_info;
        };
+       unsigned long last_rx_timestamp;
        void *desc;                     /* descriptor ring memory */
        unsigned long flags;            /* ring specific flags */
        void __iomem *tail;             /* pointer to ring tail register */
@@ -301,6 +304,32 @@ static inline int igb_desc_unused(struct igb_ring *ring)
        return ring->count + ring->next_to_clean - ring->next_to_use - 1;
 }
 
+struct igb_i2c_client_list {
+       struct i2c_client *client;
+       struct igb_i2c_client_list *next;
+};
+
+#ifdef CONFIG_IGB_HWMON
+
+#define IGB_HWMON_TYPE_LOC     0
+#define IGB_HWMON_TYPE_TEMP    1
+#define IGB_HWMON_TYPE_CAUTION 2
+#define IGB_HWMON_TYPE_MAX     3
+
+struct hwmon_attr {
+       struct device_attribute dev_attr;
+       struct e1000_hw *hw;
+       struct e1000_thermal_diode_data *sensor;
+       char name[12];
+       };
+
+struct hwmon_buff {
+       struct device *device;
+       struct hwmon_attr *hwmon_list;
+       unsigned int n_hwmon;
+       };
+#endif
+
 /* board specific private data structure */
 struct igb_adapter {
        unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -386,11 +415,22 @@ struct igb_adapter {
        struct delayed_work ptp_overflow_work;
        struct work_struct ptp_tx_work;
        struct sk_buff *ptp_tx_skb;
+       unsigned long ptp_tx_start;
+       unsigned long last_rx_ptp_check;
        spinlock_t tmreg_lock;
        struct cyclecounter cc;
        struct timecounter tc;
+       u32 tx_hwtstamp_timeouts;
+       u32 rx_hwtstamp_cleared;
 
        char fw_version[32];
+#ifdef CONFIG_IGB_HWMON
+       struct hwmon_buff igb_hwmon_buff;
+       bool ets;
+#endif
+       struct i2c_algo_bit_data i2c_algo;
+       struct i2c_adapter i2c_adap;
+       struct igb_i2c_client_list *i2c_clients;
 };
 
 #define IGB_FLAG_HAS_MSI               (1 << 0)
@@ -449,6 +489,7 @@ extern void igb_ptp_init(struct igb_adapter *adapter);
 extern void igb_ptp_stop(struct igb_adapter *adapter);
 extern void igb_ptp_reset(struct igb_adapter *adapter);
 extern void igb_ptp_tx_work(struct work_struct *work);
+extern void igb_ptp_rx_hang(struct igb_adapter *adapter);
 extern void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
 extern void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
                                struct sk_buff *skb);
@@ -466,7 +507,10 @@ static inline void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector,
 
 extern int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
                                  struct ifreq *ifr, int cmd);
-
+#ifdef CONFIG_IGB_HWMON
+extern void igb_sysfs_exit(struct igb_adapter *adapter);
+extern int igb_sysfs_init(struct igb_adapter *adapter);
+#endif
 static inline s32 igb_reset_phy(struct e1000_hw *hw)
 {
        if (hw->phy.ops.reset)
index bfe9208c4b1879db6a52695328d1640a7f3e2064..40b5d568d808745e02eb66523200068d9e5f653c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -92,6 +92,8 @@ static const struct igb_stats igb_gstrings_stats[] = {
        IGB_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
        IGB_STAT("os2bmc_tx_by_host", stats.o2bspc),
        IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc),
+       IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+       IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
 };
 
 #define IGB_NETDEV_STAT(_net_stat) { \
@@ -2272,12 +2274,21 @@ static int igb_get_ts_info(struct net_device *dev,
        struct igb_adapter *adapter = netdev_priv(dev);
 
        switch (adapter->hw.mac.type) {
+       case e1000_82575:
+               info->so_timestamping =
+                       SOF_TIMESTAMPING_TX_SOFTWARE |
+                       SOF_TIMESTAMPING_RX_SOFTWARE |
+                       SOF_TIMESTAMPING_SOFTWARE;
+               return 0;
        case e1000_82576:
        case e1000_82580:
        case e1000_i350:
        case e1000_i210:
        case e1000_i211:
                info->so_timestamping =
+                       SOF_TIMESTAMPING_TX_SOFTWARE |
+                       SOF_TIMESTAMPING_RX_SOFTWARE |
+                       SOF_TIMESTAMPING_SOFTWARE |
                        SOF_TIMESTAMPING_TX_HARDWARE |
                        SOF_TIMESTAMPING_RX_HARDWARE |
                        SOF_TIMESTAMPING_RAW_HARDWARE;
diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c
new file mode 100644 (file)
index 0000000..0a9b073
--- /dev/null
@@ -0,0 +1,242 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "igb.h"
+#include "e1000_82575.h"
+#include "e1000_hw.h"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/hwmon.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_IGB_HWMON
+/* hwmon callback functions */
+static ssize_t igb_hwmon_show_location(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+                                                    dev_attr);
+       return sprintf(buf, "loc%u\n",
+                      igb_attr->sensor->location);
+}
+
+static ssize_t igb_hwmon_show_temp(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+                                                    dev_attr);
+       unsigned int value;
+
+       /* reset the temp field */
+       igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw);
+
+       value = igb_attr->sensor->temp;
+
+       /* display millidegree */
+       value *= 1000;
+
+       return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+                                                    dev_attr);
+       unsigned int value = igb_attr->sensor->caution_thresh;
+
+       /* display millidegree */
+       value *= 1000;
+
+       return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+                                                    dev_attr);
+       unsigned int value = igb_attr->sensor->max_op_thresh;
+
+       /* display millidegree */
+       value *= 1000;
+
+       return sprintf(buf, "%u\n", value);
+}
+
+/* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
+ * @ adapter: pointer to the adapter structure
+ * @ offset: offset in the eeprom sensor data table
+ * @ type: type of sensor data to display
+ *
+ * For each file we want in hwmon's sysfs interface we need a device_attribute
+ * This is included in our hwmon_attr struct that contains the references to
+ * the data structures we need to get the data to display.
+ */
+static int igb_add_hwmon_attr(struct igb_adapter *adapter,
+                               unsigned int offset, int type) {
+       int rc;
+       unsigned int n_attr;
+       struct hwmon_attr *igb_attr;
+
+       n_attr = adapter->igb_hwmon_buff.n_hwmon;
+       igb_attr = &adapter->igb_hwmon_buff.hwmon_list[n_attr];
+
+       switch (type) {
+       case IGB_HWMON_TYPE_LOC:
+               igb_attr->dev_attr.show = igb_hwmon_show_location;
+               snprintf(igb_attr->name, sizeof(igb_attr->name),
+                        "temp%u_label", offset);
+               break;
+       case IGB_HWMON_TYPE_TEMP:
+               igb_attr->dev_attr.show = igb_hwmon_show_temp;
+               snprintf(igb_attr->name, sizeof(igb_attr->name),
+                        "temp%u_input", offset);
+               break;
+       case IGB_HWMON_TYPE_CAUTION:
+               igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh;
+               snprintf(igb_attr->name, sizeof(igb_attr->name),
+                        "temp%u_max", offset);
+               break;
+       case IGB_HWMON_TYPE_MAX:
+               igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh;
+               snprintf(igb_attr->name, sizeof(igb_attr->name),
+                        "temp%u_crit", offset);
+               break;
+       default:
+               rc = -EPERM;
+               return rc;
+       }
+
+       /* These always the same regardless of type */
+       igb_attr->sensor =
+               &adapter->hw.mac.thermal_sensor_data.sensor[offset];
+       igb_attr->hw = &adapter->hw;
+       igb_attr->dev_attr.store = NULL;
+       igb_attr->dev_attr.attr.mode = S_IRUGO;
+       igb_attr->dev_attr.attr.name = igb_attr->name;
+       sysfs_attr_init(&igb_attr->dev_attr.attr);
+       rc = device_create_file(&adapter->pdev->dev,
+                               &igb_attr->dev_attr);
+       if (rc == 0)
+               ++adapter->igb_hwmon_buff.n_hwmon;
+
+       return rc;
+}
+
+static void igb_sysfs_del_adapter(struct igb_adapter *adapter)
+{
+       int i;
+
+       if (adapter == NULL)
+               return;
+
+       for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) {
+               device_remove_file(&adapter->pdev->dev,
+                          &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr);
+       }
+
+       kfree(adapter->igb_hwmon_buff.hwmon_list);
+
+       if (adapter->igb_hwmon_buff.device)
+               hwmon_device_unregister(adapter->igb_hwmon_buff.device);
+}
+
+/* called from igb_main.c */
+void igb_sysfs_exit(struct igb_adapter *adapter)
+{
+       igb_sysfs_del_adapter(adapter);
+}
+
+/* called from igb_main.c */
+int igb_sysfs_init(struct igb_adapter *adapter)
+{
+       struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff;
+       unsigned int i;
+       int n_attrs;
+       int rc = 0;
+
+       /* If this method isn't defined we don't support thermals */
+       if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
+               goto exit;
+
+       /* Don't create thermal hwmon interface if no sensors present */
+       rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw));
+               if (rc)
+                       goto exit;
+
+       /* Allocation space for max attributes
+        * max num sensors * values (loc, temp, max, caution)
+        */
+       n_attrs = E1000_MAX_SENSORS * 4;
+       igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
+                                         GFP_KERNEL);
+       if (!igb_hwmon->hwmon_list) {
+               rc = -ENOMEM;
+               goto err;
+       }
+
+       igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev);
+       if (IS_ERR(igb_hwmon->device)) {
+               rc = PTR_ERR(igb_hwmon->device);
+               goto err;
+       }
+
+       for (i = 0; i < E1000_MAX_SENSORS; i++) {
+
+               /* Only create hwmon sysfs entries for sensors that have
+                * meaningful data.
+                */
+               if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
+                       continue;
+
+               /* Bail if any hwmon attr struct fails to initialize */
+               rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION);
+               rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC);
+               rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP);
+               rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX);
+               if (rc)
+                       goto err;
+       }
+
+       goto exit;
+
+err:
+       igb_sysfs_del_adapter(adapter);
+exit:
+       return rc;
+}
+#endif
index 31cfe2ec75dfb32b7da36311214c0ac2606015f4..a59e63040f316052ef47c40ec2b21f825591680c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -57,6 +57,7 @@
 #ifdef CONFIG_IGB_DCA
 #include <linux/dca.h>
 #endif
+#include <linux/i2c.h>
 #include "igb.h"
 
 #define MAJ 4
@@ -68,7 +69,8 @@ char igb_driver_name[] = "igb";
 char igb_driver_version[] = DRV_VERSION;
 static const char igb_driver_string[] =
                                "Intel(R) Gigabit Ethernet Network Driver";
-static const char igb_copyright[] = "Copyright (c) 2007-2012 Intel Corporation.";
+static const char igb_copyright[] =
+                               "Copyright (c) 2007-2013 Intel Corporation.";
 
 static const struct e1000_info *igb_info_tbl[] = {
        [board_82575] = &e1000_82575_info,
@@ -193,6 +195,7 @@ static const struct dev_pm_ops igb_pm_ops = {
 };
 #endif
 static void igb_shutdown(struct pci_dev *);
+static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
 #ifdef CONFIG_IGB_DCA
 static int igb_notify_dca(struct notifier_block *, unsigned long, void *);
 static struct notifier_block dca_notifier = {
@@ -234,6 +237,7 @@ static struct pci_driver igb_driver = {
        .driver.pm = &igb_pm_ops,
 #endif
        .shutdown = igb_shutdown,
+       .sriov_configure = igb_pci_sriov_configure,
        .err_handler = &igb_err_handler
 };
 
@@ -565,6 +569,91 @@ exit:
        return;
 }
 
+/*  igb_get_i2c_data - Reads the I2C SDA data bit
+ *  @hw: pointer to hardware structure
+ *  @i2cctl: Current value of I2CCTL register
+ *
+ *  Returns the I2C data bit value
+ */
+static int igb_get_i2c_data(void *data)
+{
+       struct igb_adapter *adapter = (struct igb_adapter *)data;
+       struct e1000_hw *hw = &adapter->hw;
+       s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+       return ((i2cctl & E1000_I2C_DATA_IN) != 0);
+}
+
+/* igb_set_i2c_data - Sets the I2C data bit
+ *  @data: pointer to hardware structure
+ *  @state: I2C data value (0 or 1) to set
+ *
+ *  Sets the I2C data bit
+ */
+static void igb_set_i2c_data(void *data, int state)
+{
+       struct igb_adapter *adapter = (struct igb_adapter *)data;
+       struct e1000_hw *hw = &adapter->hw;
+       s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+       if (state)
+               i2cctl |= E1000_I2C_DATA_OUT;
+       else
+               i2cctl &= ~E1000_I2C_DATA_OUT;
+
+       i2cctl &= ~E1000_I2C_DATA_OE_N;
+       i2cctl |= E1000_I2C_CLK_OE_N;
+       wr32(E1000_I2CPARAMS, i2cctl);
+       wrfl();
+
+}
+
+/* igb_set_i2c_clk - Sets the I2C SCL clock
+ *  @data: pointer to hardware structure
+ *  @state: state to set clock
+ *
+ *  Sets the I2C clock line to state
+ */
+static void igb_set_i2c_clk(void *data, int state)
+{
+       struct igb_adapter *adapter = (struct igb_adapter *)data;
+       struct e1000_hw *hw = &adapter->hw;
+       s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+       if (state) {
+               i2cctl |= E1000_I2C_CLK_OUT;
+               i2cctl &= ~E1000_I2C_CLK_OE_N;
+       } else {
+               i2cctl &= ~E1000_I2C_CLK_OUT;
+               i2cctl &= ~E1000_I2C_CLK_OE_N;
+       }
+       wr32(E1000_I2CPARAMS, i2cctl);
+       wrfl();
+}
+
+/* igb_get_i2c_clk - Gets the I2C SCL clock state
+ *  @data: pointer to hardware structure
+ *
+ *  Gets the I2C clock state
+ */
+static int igb_get_i2c_clk(void *data)
+{
+       struct igb_adapter *adapter = (struct igb_adapter *)data;
+       struct e1000_hw *hw = &adapter->hw;
+       s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+       return ((i2cctl & E1000_I2C_CLK_IN) != 0);
+}
+
+static const struct i2c_algo_bit_data igb_i2c_algo = {
+       .setsda         = igb_set_i2c_data,
+       .setscl         = igb_set_i2c_clk,
+       .getsda         = igb_get_i2c_data,
+       .getscl         = igb_get_i2c_clk,
+       .udelay         = 5,
+       .timeout        = 20,
+};
+
 /**
  * igb_get_hw_dev - return device
  * used by hardware layer to print debugging information
@@ -1708,6 +1797,18 @@ void igb_reset(struct igb_adapter *adapter)
                igb_force_mac_fc(hw);
 
        igb_init_dmac(adapter, pba);
+#ifdef CONFIG_IGB_HWMON
+       /* Re-initialize the thermal sensor on i350 devices. */
+       if (!test_bit(__IGB_DOWN, &adapter->state)) {
+               if (mac->type == e1000_i350 && hw->bus.func == 0) {
+                       /* If present, re-initialize the external thermal sensor
+                        * interface.
+                        */
+                       if (adapter->ets)
+                               mac->ops.init_thermal_sensor_thresh(hw);
+               }
+       }
+#endif
        if (!netif_running(adapter->netdev))
                igb_power_down_link(adapter);
 
@@ -1822,6 +1923,37 @@ void igb_set_fw_version(struct igb_adapter *adapter)
        return;
 }
 
+static const struct i2c_board_info i350_sensor_info = {
+       I2C_BOARD_INFO("i350bb", 0Xf8),
+};
+
+/*  igb_init_i2c - Init I2C interface
+ *  @adapter: pointer to adapter structure
+ *
+ */
+static s32 igb_init_i2c(struct igb_adapter *adapter)
+{
+       s32 status = E1000_SUCCESS;
+
+       /* I2C interface supported on i350 devices */
+       if (adapter->hw.mac.type != e1000_i350)
+               return E1000_SUCCESS;
+
+       /* Initialize the i2c bus which is controlled by the registers.
+        * This bus will use the i2c_algo_bit structue that implements
+        * the protocol through toggling of the 4 bits in the register.
+        */
+       adapter->i2c_adap.owner = THIS_MODULE;
+       adapter->i2c_algo = igb_i2c_algo;
+       adapter->i2c_algo.data = adapter;
+       adapter->i2c_adap.algo_data = &adapter->i2c_algo;
+       adapter->i2c_adap.dev.parent = &adapter->pdev->dev;
+       strlcpy(adapter->i2c_adap.name, "igb BB",
+               sizeof(adapter->i2c_adap.name));
+       status = i2c_bit_add_bus(&adapter->i2c_adap);
+       return status;
+}
+
 /**
  * igb_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -2022,9 +2154,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_err(&pdev->dev, "NVM Read Error\n");
 
        memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
-       memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len);
 
-       if (!is_valid_ether_addr(netdev->perm_addr)) {
+       if (!is_valid_ether_addr(netdev->dev_addr)) {
                dev_err(&pdev->dev, "Invalid MAC Address\n");
                err = -EIO;
                goto err_eeprom;
@@ -2115,6 +2246,13 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* reset the hardware with the new settings */
        igb_reset(adapter);
 
+       /* Init the I2C interface */
+       err = igb_init_i2c(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "failed to init i2c interface\n");
+               goto err_eeprom;
+       }
+
        /* let the f/w know that the h/w is now under the control of the
         * driver. */
        igb_get_hw_control(adapter);
@@ -2135,7 +2273,27 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
 #endif
+#ifdef CONFIG_IGB_HWMON
+       /* Initialize the thermal sensor on i350 devices. */
+       if (hw->mac.type == e1000_i350 && hw->bus.func == 0) {
+               u16 ets_word;
 
+               /*
+                * Read the NVM to determine if this i350 device supports an
+                * external thermal sensor.
+                */
+               hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_word);
+               if (ets_word != 0x0000 && ets_word != 0xFFFF)
+                       adapter->ets = true;
+               else
+                       adapter->ets = false;
+               if (igb_sysfs_init(adapter))
+                       dev_err(&pdev->dev,
+                               "failed to allocate sysfs resources\n");
+       } else {
+               adapter->ets = false;
+       }
+#endif
        /* do hw tstamp init after resetting */
        igb_ptp_init(adapter);
 
@@ -2176,6 +2334,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 err_register:
        igb_release_hw_control(adapter);
+       memset(&adapter->i2c_adap, 0, sizeof(adapter->i2c_adap));
 err_eeprom:
        if (!igb_check_reset_block(hw))
                igb_reset_phy(hw);
@@ -2196,6 +2355,111 @@ err_dma:
        return err;
 }
 
+#ifdef CONFIG_PCI_IOV
+static int  igb_disable_sriov(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       /* reclaim resources allocated to VFs */
+       if (adapter->vf_data) {
+               /* disable iov and allow time for transactions to clear */
+               if (igb_vfs_are_assigned(adapter)) {
+                       dev_warn(&pdev->dev,
+                                "Cannot deallocate SR-IOV virtual functions while they are assigned - VFs will not be deallocated\n");
+                       return -EPERM;
+               } else {
+                       pci_disable_sriov(pdev);
+                       msleep(500);
+               }
+
+               kfree(adapter->vf_data);
+               adapter->vf_data = NULL;
+               adapter->vfs_allocated_count = 0;
+               wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+               wrfl();
+               msleep(100);
+               dev_info(&pdev->dev, "IOV Disabled\n");
+
+               /* Re-enable DMA Coalescing flag since IOV is turned off */
+               adapter->flags |= IGB_FLAG_DMAC;
+       }
+
+       return 0;
+}
+
+static int igb_enable_sriov(struct pci_dev *pdev, int num_vfs)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       int old_vfs = pci_num_vf(pdev);
+       int err = 0;
+       int i;
+
+       if (!num_vfs)
+               goto out;
+       else if (old_vfs && old_vfs == num_vfs)
+               goto out;
+       else if (old_vfs && old_vfs != num_vfs)
+               err = igb_disable_sriov(pdev);
+
+       if (err)
+               goto out;
+
+       if (num_vfs > 7) {
+               err = -EPERM;
+               goto out;
+       }
+
+       adapter->vfs_allocated_count = num_vfs;
+
+       adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
+                               sizeof(struct vf_data_storage), GFP_KERNEL);
+
+       /* if allocation failed then we do not support SR-IOV */
+       if (!adapter->vf_data) {
+               adapter->vfs_allocated_count = 0;
+               dev_err(&pdev->dev,
+                       "Unable to allocate memory for VF Data Storage\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = pci_enable_sriov(pdev, adapter->vfs_allocated_count);
+       if (err)
+               goto err_out;
+
+       dev_info(&pdev->dev, "%d VFs allocated\n",
+                adapter->vfs_allocated_count);
+       for (i = 0; i < adapter->vfs_allocated_count; i++)
+               igb_vf_configure(adapter, i);
+
+       /* DMA Coalescing is not supported in IOV mode. */
+       adapter->flags &= ~IGB_FLAG_DMAC;
+       goto out;
+
+err_out:
+       kfree(adapter->vf_data);
+       adapter->vf_data = NULL;
+       adapter->vfs_allocated_count = 0;
+out:
+       return err;
+}
+
+#endif
+/*
+ *  igb_remove_i2c - Cleanup  I2C interface
+ *  @adapter: pointer to adapter structure
+ *
+ */
+static void igb_remove_i2c(struct igb_adapter *adapter)
+{
+
+       /* free the adapter bus structure */
+       i2c_del_adapter(&adapter->i2c_adap);
+}
+
 /**
  * igb_remove - Device Removal Routine
  * @pdev: PCI device information struct
@@ -2212,8 +2476,11 @@ static void igb_remove(struct pci_dev *pdev)
        struct e1000_hw *hw = &adapter->hw;
 
        pm_runtime_get_noresume(&pdev->dev);
+#ifdef CONFIG_IGB_HWMON
+       igb_sysfs_exit(adapter);
+#endif
+       igb_remove_i2c(adapter);
        igb_ptp_stop(adapter);
-
        /*
         * The watchdog timer may be rescheduled, so explicitly
         * disable watchdog from being rescheduled.
@@ -2243,23 +2510,7 @@ static void igb_remove(struct pci_dev *pdev)
        igb_clear_interrupt_scheme(adapter);
 
 #ifdef CONFIG_PCI_IOV
-       /* reclaim resources allocated to VFs */
-       if (adapter->vf_data) {
-               /* disable iov and allow time for transactions to clear */
-               if (igb_vfs_are_assigned(adapter)) {
-                       dev_info(&pdev->dev, "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
-               } else {
-                       pci_disable_sriov(pdev);
-                       msleep(500);
-               }
-
-               kfree(adapter->vf_data);
-               adapter->vf_data = NULL;
-               wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
-               wrfl();
-               msleep(100);
-               dev_info(&pdev->dev, "IOV Disabled\n");
-       }
+       igb_disable_sriov(pdev);
 #endif
 
        iounmap(hw->hw_addr);
@@ -2290,103 +2541,22 @@ static void igb_probe_vfs(struct igb_adapter *adapter)
 #ifdef CONFIG_PCI_IOV
        struct pci_dev *pdev = adapter->pdev;
        struct e1000_hw *hw = &adapter->hw;
-       int old_vfs = pci_num_vf(adapter->pdev);
-       int i;
 
        /* Virtualization features not supported on i210 family. */
        if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
                return;
 
-       if (old_vfs) {
-               dev_info(&pdev->dev, "%d pre-allocated VFs found - override "
-                        "max_vfs setting of %d\n", old_vfs, max_vfs);
-               adapter->vfs_allocated_count = old_vfs;
-       }
-
-       if (!adapter->vfs_allocated_count)
-               return;
-
-       adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
-                               sizeof(struct vf_data_storage), GFP_KERNEL);
+       igb_enable_sriov(pdev, max_vfs);
+       pci_sriov_set_totalvfs(pdev, 7);
 
-       /* if allocation failed then we do not support SR-IOV */
-       if (!adapter->vf_data) {
-               adapter->vfs_allocated_count = 0;
-               dev_err(&pdev->dev, "Unable to allocate memory for VF "
-                       "Data Storage\n");
-               goto out;
-       }
-
-       if (!old_vfs) {
-               if (pci_enable_sriov(pdev, adapter->vfs_allocated_count))
-                       goto err_out;
-       }
-       dev_info(&pdev->dev, "%d VFs allocated\n",
-                adapter->vfs_allocated_count);
-       for (i = 0; i < adapter->vfs_allocated_count; i++)
-               igb_vf_configure(adapter, i);
-
-       /* DMA Coalescing is not supported in IOV mode. */
-       adapter->flags &= ~IGB_FLAG_DMAC;
-       goto out;
-err_out:
-       kfree(adapter->vf_data);
-       adapter->vf_data = NULL;
-       adapter->vfs_allocated_count = 0;
-out:
-       return;
 #endif /* CONFIG_PCI_IOV */
 }
 
-/**
- * igb_sw_init - Initialize general software structures (struct igb_adapter)
- * @adapter: board private structure to initialize
- *
- * igb_sw_init initializes the Adapter private data structure.
- * Fields are initialized based on PCI device information and
- * OS network device settings (MTU size).
- **/
-static int igb_sw_init(struct igb_adapter *adapter)
+static void igb_init_queue_configuration(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
-       struct net_device *netdev = adapter->netdev;
-       struct pci_dev *pdev = adapter->pdev;
        u32 max_rss_queues;
 
-       pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
-
-       /* set default ring sizes */
-       adapter->tx_ring_count = IGB_DEFAULT_TXD;
-       adapter->rx_ring_count = IGB_DEFAULT_RXD;
-
-       /* set default ITR values */
-       adapter->rx_itr_setting = IGB_DEFAULT_ITR;
-       adapter->tx_itr_setting = IGB_DEFAULT_ITR;
-
-       /* set default work limits */
-       adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
-
-       adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
-                                 VLAN_HLEN;
-       adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
-
-       spin_lock_init(&adapter->stats64_lock);
-#ifdef CONFIG_PCI_IOV
-       switch (hw->mac.type) {
-       case e1000_82576:
-       case e1000_i350:
-               if (max_vfs > 7) {
-                       dev_warn(&pdev->dev,
-                                "Maximum of 7 VFs per PF, using max\n");
-                       adapter->vfs_allocated_count = 7;
-               } else
-                       adapter->vfs_allocated_count = max_vfs;
-               break;
-       default:
-               break;
-       }
-#endif /* CONFIG_PCI_IOV */
-
        /* Determine the maximum number of RSS queues supported. */
        switch (hw->mac.type) {
        case e1000_i211:
@@ -2445,6 +2615,60 @@ static int igb_sw_init(struct igb_adapter *adapter)
                        adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
                break;
        }
+}
+
+/**
+ * igb_sw_init - Initialize general software structures (struct igb_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igb_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int igb_sw_init(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+
+       pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+       /* set default ring sizes */
+       adapter->tx_ring_count = IGB_DEFAULT_TXD;
+       adapter->rx_ring_count = IGB_DEFAULT_RXD;
+
+       /* set default ITR values */
+       adapter->rx_itr_setting = IGB_DEFAULT_ITR;
+       adapter->tx_itr_setting = IGB_DEFAULT_ITR;
+
+       /* set default work limits */
+       adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
+
+       adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
+                                 VLAN_HLEN;
+       adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+       spin_lock_init(&adapter->stats64_lock);
+#ifdef CONFIG_PCI_IOV
+       switch (hw->mac.type) {
+       case e1000_82576:
+       case e1000_i350:
+               if (max_vfs > 7) {
+                       dev_warn(&pdev->dev,
+                                "Maximum of 7 VFs per PF, using max\n");
+                       adapter->vfs_allocated_count = 7;
+               } else
+                       adapter->vfs_allocated_count = max_vfs;
+               if (adapter->vfs_allocated_count)
+                       dev_warn(&pdev->dev,
+                                "Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
+               break;
+       default:
+               break;
+       }
+#endif /* CONFIG_PCI_IOV */
+
+       igb_init_queue_configuration(adapter);
 
        /* Setup and initialize a copy of the hw vlan table array */
        adapter->shadow_vfta = kzalloc(sizeof(u32) *
@@ -3768,6 +3992,7 @@ static void igb_watchdog_task(struct work_struct *work)
        }
 
        igb_spoof_check(adapter);
+       igb_ptp_rx_hang(adapter);
 
        /* Reset the timer */
        if (!test_bit(__IGB_DOWN, &adapter->state))
@@ -4387,12 +4612,15 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
        first->bytecount = skb->len;
        first->gso_segs = 1;
 
+       skb_tx_timestamp(skb);
+
        if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
                     !(adapter->ptp_tx_skb))) {
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                tx_flags |= IGB_TX_FLAGS_TSTAMP;
 
                adapter->ptp_tx_skb = skb_get(skb);
+               adapter->ptp_tx_start = jiffies;
                if (adapter->hw.mac.type == e1000_82576)
                        schedule_work(&adapter->ptp_tx_work);
        }
@@ -4969,7 +5197,7 @@ static int igb_vf_configure(struct igb_adapter *adapter, int vf)
 {
        unsigned char mac_addr[ETH_ALEN];
 
-       eth_random_addr(mac_addr);
+       eth_zero_addr(mac_addr);
        igb_set_vf_mac(adapter, vf, mac_addr);
 
        return 0;
@@ -5322,9 +5550,9 @@ static void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
 {
        unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
 
-       /* generate a new mac address as we were hotplug removed/added */
+       /* clear mac address as we were hotplug removed/added */
        if (!(adapter->vf_data[vf].flags & IGB_VF_FLAG_PF_SET_MAC))
-               eth_random_addr(vf_mac);
+               eth_zero_addr(vf_mac);
 
        /* process remaining reset events */
        igb_vf_reset(adapter, vf);
@@ -5703,7 +5931,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
                        break;
 
                /* prevent any other reads prior to eop_desc */
-               rmb();
+               read_barrier_depends();
 
                /* if DD is not set pending work has not been completed */
                if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
@@ -6903,6 +7131,72 @@ static void igb_shutdown(struct pci_dev *pdev)
        }
 }
 
+#ifdef CONFIG_PCI_IOV
+static int igb_sriov_reinit(struct pci_dev *dev)
+{
+       struct net_device *netdev = pci_get_drvdata(dev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct pci_dev *pdev = adapter->pdev;
+
+       rtnl_lock();
+
+       if (netif_running(netdev))
+               igb_close(netdev);
+
+       igb_clear_interrupt_scheme(adapter);
+
+       igb_init_queue_configuration(adapter);
+
+       if (igb_init_interrupt_scheme(adapter, true)) {
+               dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+               return -ENOMEM;
+       }
+
+       if (netif_running(netdev))
+               igb_open(netdev);
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static int igb_pci_disable_sriov(struct pci_dev *dev)
+{
+       int err = igb_disable_sriov(dev);
+
+       if (!err)
+               err = igb_sriov_reinit(dev);
+
+       return err;
+}
+
+static int igb_pci_enable_sriov(struct pci_dev *dev, int num_vfs)
+{
+       int err = igb_enable_sriov(dev, num_vfs);
+
+       if (err)
+               goto out;
+
+       err = igb_sriov_reinit(dev);
+       if (!err)
+               return num_vfs;
+
+out:
+       return err;
+}
+
+#endif
+static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+       if (num_vfs == 0)
+               return igb_pci_disable_sriov(dev);
+       else
+               return igb_pci_enable_sriov(dev, num_vfs);
+#endif
+       return 0;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Polling 'interrupt' - used by things like netconsole to send skbs
@@ -7308,4 +7602,138 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
        }
 }
 
+static DEFINE_SPINLOCK(i2c_clients_lock);
+
+/*  igb_get_i2c_client - returns matching client
+ *  in adapters's client list.
+ *  @adapter: adapter struct
+ *  @dev_addr: device address of i2c needed.
+ */
+struct i2c_client *
+igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr)
+{
+       ulong flags;
+       struct igb_i2c_client_list *client_list;
+       struct i2c_client *client = NULL;
+       struct i2c_board_info client_info = {
+               I2C_BOARD_INFO("igb", 0x00),
+       };
+
+       spin_lock_irqsave(&i2c_clients_lock, flags);
+       client_list = adapter->i2c_clients;
+
+       /* See if we already have an i2c_client */
+       while (client_list) {
+               if (client_list->client->addr == (dev_addr >> 1)) {
+                       client = client_list->client;
+                       goto exit;
+               } else {
+                       client_list = client_list->next;
+               }
+       }
+
+       /* no client_list found, create a new one as long as
+        * irqs are not disabled
+        */
+       if (unlikely(irqs_disabled()))
+               goto exit;
+
+       client_list = kzalloc(sizeof(*client_list), GFP_KERNEL);
+       if (client_list == NULL)
+               goto exit;
+
+       /* dev_addr passed to us is left-shifted by 1 bit
+        * i2c_new_device call expects it to be flush to the right.
+        */
+       client_info.addr = dev_addr >> 1;
+       client_info.platform_data = adapter;
+       client_list->client = i2c_new_device(&adapter->i2c_adap, &client_info);
+       if (client_list->client == NULL) {
+               dev_info(&adapter->pdev->dev,
+                       "Failed to create new i2c device..\n");
+               goto err_no_client;
+       }
+
+       /* insert new client at head of list */
+       client_list->next = adapter->i2c_clients;
+       adapter->i2c_clients = client_list;
+
+       client = client_list->client;
+       goto exit;
+
+err_no_client:
+       kfree(client_list);
+exit:
+       spin_unlock_irqrestore(&i2c_clients_lock, flags);
+       return client;
+}
+
+/*  igb_read_i2c_byte - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @dev_addr: device address
+ *  @data: value read
+ *
+ *  Performs byte read operation over I2C interface at
+ *  a specified device address.
+ */
+s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+                               u8 dev_addr, u8 *data)
+{
+       struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
+       struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr);
+       s32 status;
+       u16 swfw_mask = 0;
+
+       if (!this_client)
+               return E1000_ERR_I2C;
+
+       swfw_mask = E1000_SWFW_PHY0_SM;
+
+       if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)
+           != E1000_SUCCESS)
+               return E1000_ERR_SWFW_SYNC;
+
+       status = i2c_smbus_read_byte_data(this_client, byte_offset);
+       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+
+       if (status < 0)
+               return E1000_ERR_I2C;
+       else {
+               *data = status;
+               return E1000_SUCCESS;
+       }
+}
+
+/*  igb_write_i2c_byte - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @dev_addr: device address
+ *  @data: value to write
+ *
+ *  Performs byte write operation over I2C interface at
+ *  a specified device address.
+ */
+s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+                                u8 dev_addr, u8 data)
+{
+       struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
+       struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr);
+       s32 status;
+       u16 swfw_mask = E1000_SWFW_PHY0_SM;
+
+       if (!this_client)
+               return E1000_ERR_I2C;
+
+       if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != E1000_SUCCESS)
+               return E1000_ERR_SWFW_SYNC;
+       status = i2c_smbus_write_byte_data(this_client, byte_offset, data);
+       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+
+       if (status)
+               return E1000_ERR_I2C;
+       else
+               return E1000_SUCCESS;
+
+}
 /* igb_main.c */
index ab3429729bde4134a0310a6199cf9eb1737369b6..0987822359f00590d7f36bc5e126c8a4f20ee1ac 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/pci.h>
+#include <linux/ptp_classify.h>
 
 #include "igb.h"
 
@@ -70,6 +71,7 @@
  */
 
 #define IGB_SYSTIM_OVERFLOW_PERIOD     (HZ * 60 * 9)
+#define IGB_PTP_TX_TIMEOUT             (HZ * 15)
 #define INCPERIOD_82576                        (1 << E1000_TIMINCA_16NS_SHIFT)
 #define INCVALUE_82576_MASK            ((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
 #define INCVALUE_82576                 (16 << IGB_82576_TSYNC_SHIFT)
@@ -396,6 +398,15 @@ void igb_ptp_tx_work(struct work_struct *work)
        if (!adapter->ptp_tx_skb)
                return;
 
+       if (time_is_before_jiffies(adapter->ptp_tx_start +
+                                  IGB_PTP_TX_TIMEOUT)) {
+               dev_kfree_skb_any(adapter->ptp_tx_skb);
+               adapter->ptp_tx_skb = NULL;
+               adapter->tx_hwtstamp_timeouts++;
+               dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang");
+               return;
+       }
+
        tsynctxctl = rd32(E1000_TSYNCTXCTL);
        if (tsynctxctl & E1000_TSYNCTXCTL_VALID)
                igb_ptp_tx_hwtstamp(adapter);
@@ -418,6 +429,51 @@ static void igb_ptp_overflow_check(struct work_struct *work)
                              IGB_SYSTIM_OVERFLOW_PERIOD);
 }
 
+/**
+ * igb_ptp_rx_hang - detect error case when Rx timestamp registers latched
+ * @adapter: private network adapter structure
+ *
+ * This watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
+ */
+void igb_ptp_rx_hang(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct igb_ring *rx_ring;
+       u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL);
+       unsigned long rx_event;
+       int n;
+
+       if (hw->mac.type != e1000_82576)
+               return;
+
+       /* If we don't have a valid timestamp in the registers, just update the
+        * timeout counter and exit
+        */
+       if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) {
+               adapter->last_rx_ptp_check = jiffies;
+               return;
+       }
+
+       /* Determine the most recent watchdog or rx_timestamp event */
+       rx_event = adapter->last_rx_ptp_check;
+       for (n = 0; n < adapter->num_rx_queues; n++) {
+               rx_ring = adapter->rx_ring[n];
+               if (time_after(rx_ring->last_rx_timestamp, rx_event))
+                       rx_event = rx_ring->last_rx_timestamp;
+       }
+
+       /* Only need to read the high RXSTMP register to clear the lock */
+       if (time_is_before_jiffies(rx_event + 5 * HZ)) {
+               rd32(E1000_RXSTMPH);
+               adapter->last_rx_ptp_check = jiffies;
+               adapter->rx_hwtstamp_cleared++;
+               dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang");
+       }
+}
+
 /**
  * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
  * @adapter: Board private structure.
@@ -643,7 +699,6 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
        else
                wr32(E1000_ETQF(3), 0);
 
-#define PTP_PORT 319
        /* L4 Queue Filter[3]: filter by destination port and protocol */
        if (is_l4) {
                u32 ftqf = (IPPROTO_UDP /* UDP */
@@ -652,12 +707,12 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
                        | E1000_FTQF_MASK); /* mask all inputs */
                ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
 
-               wr32(E1000_IMIR(3), htons(PTP_PORT));
+               wr32(E1000_IMIR(3), htons(PTP_EV_PORT));
                wr32(E1000_IMIREXT(3),
                     (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
                if (hw->mac.type == e1000_82576) {
                        /* enable source port check */
-                       wr32(E1000_SPQF(3), htons(PTP_PORT));
+                       wr32(E1000_SPQF(3), htons(PTP_EV_PORT));
                        ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
                }
                wr32(E1000_FTQF(3), ftqf);
@@ -801,6 +856,10 @@ void igb_ptp_stop(struct igb_adapter *adapter)
        }
 
        cancel_work_sync(&adapter->ptp_tx_work);
+       if (adapter->ptp_tx_skb) {
+               dev_kfree_skb_any(adapter->ptp_tx_skb);
+               adapter->ptp_tx_skb = NULL;
+       }
 
        if (adapter->ptp_clock) {
                ptp_clock_unregister(adapter->ptp_clock);
index 277f5dfe3d900dede1ff0cc83a061a2cc92a6ed4..8224889e6845aa61488a4613adb8e5f9e649712f 100644 (file)
@@ -1738,7 +1738,6 @@ static int igbvf_set_mac(struct net_device *netdev, void *p)
                return -EADDRNOTAVAIL;
 
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-       netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
        return 0;
 }
@@ -2736,30 +2735,24 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        err = hw->mac.ops.reset_hw(hw);
        if (err) {
                dev_info(&pdev->dev,
-                        "PF still in reset state, assigning new address."
-                        " Is the PF interface up?\n");
-               eth_hw_addr_random(netdev);
-               memcpy(adapter->hw.mac.addr, netdev->dev_addr,
-                       netdev->addr_len);
+                        "PF still in reset state. Is the PF interface up?\n");
        } else {
                err = hw->mac.ops.read_mac_addr(hw);
-               if (err) {
-                       dev_err(&pdev->dev, "Error reading MAC address\n");
-                       goto err_hw_init;
-               }
+               if (err)
+                       dev_info(&pdev->dev, "Error reading MAC address.\n");
+               else if (is_zero_ether_addr(adapter->hw.mac.addr))
+                       dev_info(&pdev->dev, "MAC address not assigned by administrator.\n");
                memcpy(netdev->dev_addr, adapter->hw.mac.addr,
-                       netdev->addr_len);
+                      netdev->addr_len);
        }
 
        if (!is_valid_ether_addr(netdev->dev_addr)) {
-               dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
-                       netdev->dev_addr);
-               err = -EIO;
-               goto err_hw_init;
+               dev_info(&pdev->dev, "Assigning random MAC address.\n");
+               eth_hw_addr_random(netdev);
+               memcpy(adapter->hw.mac.addr, netdev->dev_addr,
+                       netdev->addr_len);
        }
 
-       memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
-
        setup_timer(&adapter->watchdog_timer, &igbvf_watchdog,
                    (unsigned long) adapter);
 
index ae96c10251be9c0ac64c7ca25a72993ae7eae22c..c7564123dd311b06af9a59adbe48d547ce69e08a 100644 (file)
@@ -500,9 +500,8 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
-       memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
 
-       if (!is_valid_ether_addr(netdev->perm_addr)) {
+       if (!is_valid_ether_addr(netdev->dev_addr)) {
                netif_err(adapter, probe, adapter->netdev, "Invalid MAC Address\n");
                err = -EIO;
                goto err_eeprom;
index 8e786764c60ea186084a7c5b18e9641abeef2a0e..8371ae4265fe6d3ccc1101bf3f07df9c5205b8a9 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/cpumask.h>
 #include <linux/aer.h>
 #include <linux/if_vlan.h>
+#include <linux/jiffies.h>
 
 #include <linux/clocksource.h>
 #include <linux/net_tstamp.h>
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
 #define IXGBE_RX_BUFFER_WRITE  16      /* Must be power of 2 */
 
-#define IXGBE_TX_FLAGS_CSUM            (u32)(1)
-#define IXGBE_TX_FLAGS_HW_VLAN         (u32)(1 << 1)
-#define IXGBE_TX_FLAGS_SW_VLAN         (u32)(1 << 2)
-#define IXGBE_TX_FLAGS_TSO             (u32)(1 << 3)
-#define IXGBE_TX_FLAGS_IPV4            (u32)(1 << 4)
-#define IXGBE_TX_FLAGS_FCOE            (u32)(1 << 5)
-#define IXGBE_TX_FLAGS_FSO             (u32)(1 << 6)
-#define IXGBE_TX_FLAGS_TXSW            (u32)(1 << 7)
-#define IXGBE_TX_FLAGS_TSTAMP          (u32)(1 << 8)
-#define IXGBE_TX_FLAGS_NO_IFCS         (u32)(1 << 9)
+enum ixgbe_tx_flags {
+       /* cmd_type flags */
+       IXGBE_TX_FLAGS_HW_VLAN  = 0x01,
+       IXGBE_TX_FLAGS_TSO      = 0x02,
+       IXGBE_TX_FLAGS_TSTAMP   = 0x04,
+
+       /* olinfo flags */
+       IXGBE_TX_FLAGS_CC       = 0x08,
+       IXGBE_TX_FLAGS_IPV4     = 0x10,
+       IXGBE_TX_FLAGS_CSUM     = 0x20,
+
+       /* software defined flags */
+       IXGBE_TX_FLAGS_SW_VLAN  = 0x40,
+       IXGBE_TX_FLAGS_FCOE     = 0x80,
+};
+
+/* VLAN info */
 #define IXGBE_TX_FLAGS_VLAN_MASK       0xffff0000
 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK  0xe0000000
 #define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT  29
@@ -224,6 +232,7 @@ struct ixgbe_ring {
                struct ixgbe_tx_buffer *tx_buffer_info;
                struct ixgbe_rx_buffer *rx_buffer_info;
        };
+       unsigned long last_rx_timestamp;
        unsigned long state;
        u8 __iomem *tail;
        dma_addr_t dma;                 /* phys. address of descriptor ring */
@@ -573,11 +582,14 @@ struct ixgbe_adapter {
 
        struct ptp_clock *ptp_clock;
        struct ptp_clock_info ptp_caps;
+       struct work_struct ptp_tx_work;
+       struct sk_buff *ptp_tx_skb;
+       unsigned long ptp_tx_start;
        unsigned long last_overflow_check;
+       unsigned long last_rx_ptp_check;
        spinlock_t tmreg_lock;
        struct cyclecounter cc;
        struct timecounter tc;
-       int rx_hwtstamp_filter;
        u32 base_incval;
 
        /* SR-IOV */
@@ -742,15 +754,32 @@ static inline struct netdev_queue *txring_txq(const struct ixgbe_ring *ring)
 extern void ixgbe_ptp_init(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
-extern void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
-                                 struct sk_buff *skb);
-extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
-                                 union ixgbe_adv_rx_desc *rx_desc,
-                                 struct sk_buff *skb);
+extern void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter);
+extern void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+                                   struct sk_buff *skb);
+static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
+                                        union ixgbe_adv_rx_desc *rx_desc,
+                                        struct sk_buff *skb)
+{
+       if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
+               return;
+
+       __ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb);
+
+       /*
+        * Update the last_rx_timestamp timer in order to enable watchdog check
+        * for error case of latched timestamp on a dropped packet.
+        */
+       rx_ring->last_rx_timestamp = jiffies;
+}
+
 extern int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
                                    struct ifreq *ifr, int cmd);
 extern void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_reset(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr);
+#ifdef CONFIG_PCI_IOV
+void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter);
+#endif
 
 #endif /* _IXGBE_H_ */
index f1e002d5fa8f5dfb53c9d865dab1fd558bf7ea7b..6718fb42ce1a60e8f59dcd1bcd5e69753d7edc9e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/dcbnl.h>
 #include "ixgbe_dcb_82598.h"
 #include "ixgbe_dcb_82599.h"
+#include "ixgbe_sriov.h"
 
 /* Callbacks for DCB netlink in the kernel */
 #define BIT_DCB_MODE   0x01
@@ -643,9 +644,11 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev,
                return err;
 
        err = dcb_ieee_setapp(dev, app);
+       if (err)
+               return err;
 
 #ifdef IXGBE_FCOE
-       if (!err && app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+       if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
            app->protocol == ETH_P_FCOE) {
                u8 app_mask = dcb_ieee_getapp_mask(dev, app);
 
@@ -656,6 +659,23 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev,
                ixgbe_dcbnl_devreset(dev);
        }
 #endif
+
+       /* VF devices should use default UP when available */
+       if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+           app->protocol == 0) {
+               int vf;
+
+               adapter->default_up = app->priority;
+
+               for (vf = 0; vf < adapter->num_vfs; vf++) {
+                       struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+                       if (!vfinfo->pf_qos)
+                               ixgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+                                               app->priority, vf);
+               }
+       }
+
        return 0;
 }
 
@@ -683,6 +703,24 @@ static int ixgbe_dcbnl_ieee_delapp(struct net_device *dev,
                ixgbe_dcbnl_devreset(dev);
        }
 #endif
+       /* IF default priority is being removed clear VF default UP */
+       if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+           app->protocol == 0 && adapter->default_up == app->priority) {
+               int vf;
+               long unsigned int app_mask = dcb_ieee_getapp_mask(dev, app);
+               int qos = app_mask ? find_first_bit(&app_mask, 8) : 0;
+
+               adapter->default_up = qos;
+
+               for (vf = 0; vf < adapter->num_vfs; vf++) {
+                       struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+                       if (!vfinfo->pf_qos)
+                               ixgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+                                               qos, vf);
+               }
+       }
+
        return err;
 }
 
index 32685842434565e609a5f8589b67497609074aa4..1513b1052ee2f3616cae4931397605b97c317c34 100644 (file)
@@ -1837,19 +1837,11 @@ static void ixgbe_diag_test(struct net_device *netdev,
                             struct ethtool_test *eth_test, u64 *data)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
        bool if_running = netif_running(netdev);
 
        set_bit(__IXGBE_TESTING, &adapter->state);
        if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
-               /* Offline tests */
-
-               e_info(hw, "offline testing starting\n");
-
-               /* Link test performed before hardware reset so autoneg doesn't
-                * interfere with test result */
-               if (ixgbe_link_test(adapter, &data[4]))
-                       eth_test->flags |= ETH_TEST_FL_FAILED;
-
                if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
                        int i;
                        for (i = 0; i < adapter->num_vfs; i++) {
@@ -1870,12 +1862,24 @@ static void ixgbe_diag_test(struct net_device *netdev,
                        }
                }
 
+               /* Offline tests */
+               e_info(hw, "offline testing starting\n");
+
                if (if_running)
                        /* indicate we're in test mode */
                        dev_close(netdev);
-               else
-                       ixgbe_reset(adapter);
 
+               /* bringing adapter down disables SFP+ optics */
+               if (hw->mac.ops.enable_tx_laser)
+                       hw->mac.ops.enable_tx_laser(hw);
+
+               /* Link test performed before hardware reset so autoneg doesn't
+                * interfere with test result
+                */
+               if (ixgbe_link_test(adapter, &data[4]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               ixgbe_reset(adapter);
                e_info(hw, "register testing starting\n");
                if (ixgbe_reg_test(adapter, &data[0]))
                        eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1908,16 +1912,22 @@ static void ixgbe_diag_test(struct net_device *netdev,
 skip_loopback:
                ixgbe_reset(adapter);
 
+               /* clear testing bit and return adapter to previous state */
                clear_bit(__IXGBE_TESTING, &adapter->state);
                if (if_running)
                        dev_open(netdev);
        } else {
                e_info(hw, "online testing starting\n");
+
+               /* if adapter is down, SFP+ optics will be disabled */
+               if (!if_running && hw->mac.ops.enable_tx_laser)
+                       hw->mac.ops.enable_tx_laser(hw);
+
                /* Online tests */
                if (ixgbe_link_test(adapter, &data[4]))
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
-               /* Online tests aren't run; pass by default */
+               /* Offline tests aren't run; pass by default */
                data[0] = 0;
                data[1] = 0;
                data[2] = 0;
@@ -1925,6 +1935,10 @@ skip_loopback:
 
                clear_bit(__IXGBE_TESTING, &adapter->state);
        }
+
+       /* if adapter was down, ensure SFP+ optics are disabled again */
+       if (!if_running && hw->mac.ops.disable_tx_laser)
+               hw->mac.ops.disable_tx_laser(hw);
 skip_ol_tests:
        msleep_interruptible(4 * 1000);
 }
@@ -2695,6 +2709,14 @@ static int ixgbe_get_ts_info(struct net_device *dev,
                        (1 << HWTSTAMP_FILTER_NONE) |
                        (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
                        (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+                       (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
                        (1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
                break;
        default:
index 252850d9a3e0925b45bcb3524dd7c6e490540616..496836765df8868990241f9e026c5f9e67e6a0da 100644 (file)
@@ -544,15 +544,14 @@ int ixgbe_fso(struct ixgbe_ring *tx_ring,
                first->gso_segs = DIV_ROUND_UP(skb->len - *hdr_len,
                                               skb_shinfo(skb)->gso_size);
                first->bytecount += (first->gso_segs - 1) * *hdr_len;
-               first->tx_flags |= IXGBE_TX_FLAGS_FSO;
+               first->tx_flags |= IXGBE_TX_FLAGS_TSO;
        }
 
        /* set flag indicating FCOE to ixgbe_tx_map call */
-       first->tx_flags |= IXGBE_TX_FLAGS_FCOE;
+       first->tx_flags |= IXGBE_TX_FLAGS_FCOE | IXGBE_TX_FLAGS_CC;
 
-       /* mss_l4len_id: use 1 for FSO as TSO, no need for L4LEN */
+       /* mss_l4len_id: use 0 for FSO as TSO, no need for L4LEN */
        mss_l4len_idx = skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
-       mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
 
        /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
        vlan_macip_lens = skb_transport_offset(skb) +
index 20a5af6d87d0e8747027964ba01a03bd7e3ca24c..5989b3fa9fdc7432a8a00f4fa58e148935799e74 100644 (file)
@@ -803,6 +803,7 @@ static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter)
        /* Do the reset outside of interrupt context */
        if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
                adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+               e_warn(drv, "initiating reset due to tx timeout\n");
                ixgbe_service_event_schedule(adapter);
        }
 }
@@ -850,9 +851,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
                total_bytes += tx_buffer->bytecount;
                total_packets += tx_buffer->gso_segs;
 
-               if (unlikely(tx_buffer->tx_flags & IXGBE_TX_FLAGS_TSTAMP))
-                       ixgbe_ptp_tx_hwtstamp(q_vector, tx_buffer->skb);
-
                /* free the skb */
                dev_kfree_skb_any(tx_buffer->skb);
 
@@ -1441,7 +1439,7 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
 
        ixgbe_rx_checksum(rx_ring, rx_desc, skb);
 
-       ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, rx_desc, skb);
+       ixgbe_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
 
        if ((dev->features & NETIF_F_HW_VLAN_RX) &&
            ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
@@ -5534,6 +5532,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
                break;
        }
 
+       adapter->last_rx_ptp_check = jiffies;
+
        if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED)
                ixgbe_ptp_start_cyclecounter(adapter);
 
@@ -5614,6 +5614,7 @@ static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
                         * to get done, so reset controller to flush Tx.
                         * (Do the reset outside of interrupt context).
                         */
+                       e_warn(drv, "initiating reset to clear Tx work after link loss\n");
                        adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
                }
        }
@@ -5878,7 +5879,6 @@ static void ixgbe_service_task(struct work_struct *work)
        struct ixgbe_adapter *adapter = container_of(work,
                                                     struct ixgbe_adapter,
                                                     service_task);
-
        ixgbe_reset_subtask(adapter);
        ixgbe_sfp_detection_subtask(adapter);
        ixgbe_sfp_link_config_subtask(adapter);
@@ -5886,7 +5886,11 @@ static void ixgbe_service_task(struct work_struct *work)
        ixgbe_watchdog_subtask(adapter);
        ixgbe_fdir_reinit_subtask(adapter);
        ixgbe_check_hang_subtask(adapter);
-       ixgbe_ptp_overflow_check(adapter);
+
+       if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) {
+               ixgbe_ptp_overflow_check(adapter);
+               ixgbe_ptp_rx_hang(adapter);
+       }
 
        ixgbe_service_event_complete(adapter);
 }
@@ -5899,6 +5903,9 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
        u32 vlan_macip_lens, type_tucmd;
        u32 mss_l4len_idx, l4len;
 
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
        if (!skb_is_gso(skb))
                return 0;
 
@@ -5941,10 +5948,9 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
        first->gso_segs = skb_shinfo(skb)->gso_segs;
        first->bytecount += (first->gso_segs - 1) * *hdr_len;
 
-       /* mss_l4len_id: use 1 as index for TSO */
+       /* mss_l4len_id: use 0 as index for TSO */
        mss_l4len_idx = l4len << IXGBE_ADVTXD_L4LEN_SHIFT;
        mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
-       mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
 
        /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
        vlan_macip_lens = skb_network_header_len(skb);
@@ -5966,12 +5972,9 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
        u32 type_tucmd = 0;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL) {
-               if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN)) {
-                       if (unlikely(skb->no_fcs))
-                               first->tx_flags |= IXGBE_TX_FLAGS_NO_IFCS;
-                       if (!(first->tx_flags & IXGBE_TX_FLAGS_TXSW))
-                               return;
-               }
+               if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
+                   !(first->tx_flags & IXGBE_TX_FLAGS_CC))
+                       return;
        } else {
                u8 l4_hdr = 0;
                switch (first->protocol) {
@@ -6029,30 +6032,32 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
                          type_tucmd, mss_l4len_idx);
 }
 
-static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
+#define IXGBE_SET_FLAG(_input, _flag, _result) \
+       ((_flag <= _result) ? \
+        ((u32)(_input & _flag) * (_result / _flag)) : \
+        ((u32)(_input & _flag) / (_flag / _result)))
+
+static u32 ixgbe_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
 {
        /* set type for advanced descriptor with frame checksum insertion */
-       __le32 cmd_type = cpu_to_le32(IXGBE_ADVTXD_DTYP_DATA |
-                                     IXGBE_ADVTXD_DCMD_DEXT);
+       u32 cmd_type = IXGBE_ADVTXD_DTYP_DATA |
+                      IXGBE_ADVTXD_DCMD_DEXT |
+                      IXGBE_ADVTXD_DCMD_IFCS;
 
        /* set HW vlan bit if vlan is present */
-       if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN)
-               cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE);
-
-       if (tx_flags & IXGBE_TX_FLAGS_TSTAMP)
-               cmd_type |= cpu_to_le32(IXGBE_ADVTXD_MAC_TSTAMP);
+       cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_HW_VLAN,
+                                  IXGBE_ADVTXD_DCMD_VLE);
 
        /* set segmentation enable bits for TSO/FSO */
-#ifdef IXGBE_FCOE
-       if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FSO))
-#else
-       if (tx_flags & IXGBE_TX_FLAGS_TSO)
-#endif
-               cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_TSE);
+       cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_TSO,
+                                  IXGBE_ADVTXD_DCMD_TSE);
+
+       /* set timestamp bit if present */
+       cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_TSTAMP,
+                                  IXGBE_ADVTXD_MAC_TSTAMP);
 
        /* insert frame checksum */
-       if (!(tx_flags & IXGBE_TX_FLAGS_NO_IFCS))
-               cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_IFCS);
+       cmd_type ^= IXGBE_SET_FLAG(skb->no_fcs, 1, IXGBE_ADVTXD_DCMD_IFCS);
 
        return cmd_type;
 }
@@ -6060,36 +6065,27 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
 static void ixgbe_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
                                   u32 tx_flags, unsigned int paylen)
 {
-       __le32 olinfo_status = cpu_to_le32(paylen << IXGBE_ADVTXD_PAYLEN_SHIFT);
+       u32 olinfo_status = paylen << IXGBE_ADVTXD_PAYLEN_SHIFT;
 
        /* enable L4 checksum for TSO and TX checksum offload */
-       if (tx_flags & IXGBE_TX_FLAGS_CSUM)
-               olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_TXSM);
+       olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+                                       IXGBE_TX_FLAGS_CSUM,
+                                       IXGBE_ADVTXD_POPTS_TXSM);
 
        /* enble IPv4 checksum for TSO */
-       if (tx_flags & IXGBE_TX_FLAGS_IPV4)
-               olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IXSM);
-
-       /* use index 1 context for TSO/FSO/FCOE */
-#ifdef IXGBE_FCOE
-       if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FCOE))
-#else
-       if (tx_flags & IXGBE_TX_FLAGS_TSO)
-#endif
-               olinfo_status |= cpu_to_le32(1 << IXGBE_ADVTXD_IDX_SHIFT);
+       olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+                                       IXGBE_TX_FLAGS_IPV4,
+                                       IXGBE_ADVTXD_POPTS_IXSM);
 
        /*
         * Check Context must be set if Tx switch is enabled, which it
         * always is for case where virtual functions are running
         */
-#ifdef IXGBE_FCOE
-       if (tx_flags & (IXGBE_TX_FLAGS_TXSW | IXGBE_TX_FLAGS_FCOE))
-#else
-       if (tx_flags & IXGBE_TX_FLAGS_TXSW)
-#endif
-               olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_CC);
+       olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+                                       IXGBE_TX_FLAGS_CC,
+                                       IXGBE_ADVTXD_CC);
 
-       tx_desc->read.olinfo_status = olinfo_status;
+       tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
 #define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
@@ -6099,22 +6095,22 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
                         struct ixgbe_tx_buffer *first,
                         const u8 hdr_len)
 {
-       dma_addr_t dma;
        struct sk_buff *skb = first->skb;
        struct ixgbe_tx_buffer *tx_buffer;
        union ixgbe_adv_tx_desc *tx_desc;
-       struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
-       unsigned int data_len = skb->data_len;
-       unsigned int size = skb_headlen(skb);
-       unsigned int paylen = skb->len - hdr_len;
+       struct skb_frag_struct *frag;
+       dma_addr_t dma;
+       unsigned int data_len, size;
        u32 tx_flags = first->tx_flags;
-       __le32 cmd_type;
+       u32 cmd_type = ixgbe_tx_cmd_type(skb, tx_flags);
        u16 i = tx_ring->next_to_use;
 
        tx_desc = IXGBE_TX_DESC(tx_ring, i);
 
-       ixgbe_tx_olinfo_status(tx_desc, tx_flags, paylen);
-       cmd_type = ixgbe_tx_cmd_type(tx_flags);
+       ixgbe_tx_olinfo_status(tx_desc, tx_flags, skb->len - hdr_len);
+
+       size = skb_headlen(skb);
+       data_len = skb->data_len;
 
 #ifdef IXGBE_FCOE
        if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
@@ -6128,19 +6124,22 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
 
 #endif
        dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
-       if (dma_mapping_error(tx_ring->dev, dma))
-               goto dma_error;
 
-       /* record length, and DMA address */
-       dma_unmap_len_set(first, len, size);
-       dma_unmap_addr_set(first, dma, dma);
+       tx_buffer = first;
 
-       tx_desc->read.buffer_addr = cpu_to_le64(dma);
+       for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
+               if (dma_mapping_error(tx_ring->dev, dma))
+                       goto dma_error;
+
+               /* record length, and DMA address */
+               dma_unmap_len_set(tx_buffer, len, size);
+               dma_unmap_addr_set(tx_buffer, dma, dma);
+
+               tx_desc->read.buffer_addr = cpu_to_le64(dma);
 
-       for (;;) {
                while (unlikely(size > IXGBE_MAX_DATA_PER_TXD)) {
                        tx_desc->read.cmd_type_len =
-                               cmd_type | cpu_to_le32(IXGBE_MAX_DATA_PER_TXD);
+                               cpu_to_le32(cmd_type ^ IXGBE_MAX_DATA_PER_TXD);
 
                        i++;
                        tx_desc++;
@@ -6148,18 +6147,18 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
                                tx_desc = IXGBE_TX_DESC(tx_ring, 0);
                                i = 0;
                        }
+                       tx_desc->read.olinfo_status = 0;
 
                        dma += IXGBE_MAX_DATA_PER_TXD;
                        size -= IXGBE_MAX_DATA_PER_TXD;
 
                        tx_desc->read.buffer_addr = cpu_to_le64(dma);
-                       tx_desc->read.olinfo_status = 0;
                }
 
                if (likely(!data_len))
                        break;
 
-               tx_desc->read.cmd_type_len = cmd_type | cpu_to_le32(size);
+               tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type ^ size);
 
                i++;
                tx_desc++;
@@ -6167,6 +6166,7 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
                        tx_desc = IXGBE_TX_DESC(tx_ring, 0);
                        i = 0;
                }
+               tx_desc->read.olinfo_status = 0;
 
 #ifdef IXGBE_FCOE
                size = min_t(unsigned int, data_len, skb_frag_size(frag));
@@ -6177,22 +6177,13 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
 
                dma = skb_frag_dma_map(tx_ring->dev, frag, 0, size,
                                       DMA_TO_DEVICE);
-               if (dma_mapping_error(tx_ring->dev, dma))
-                       goto dma_error;
 
                tx_buffer = &tx_ring->tx_buffer_info[i];
-               dma_unmap_len_set(tx_buffer, len, size);
-               dma_unmap_addr_set(tx_buffer, dma, dma);
-
-               tx_desc->read.buffer_addr = cpu_to_le64(dma);
-               tx_desc->read.olinfo_status = 0;
-
-               frag++;
        }
 
        /* write last descriptor with RS and EOP bits */
-       cmd_type |= cpu_to_le32(size) | cpu_to_le32(IXGBE_TXD_CMD);
-       tx_desc->read.cmd_type_len = cmd_type;
+       cmd_type |= size | IXGBE_TXD_CMD;
+       tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
 
        netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
 
@@ -6445,6 +6436,11 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
        if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
+
+               /* schedule check for Tx timestamp */
+               adapter->ptp_tx_skb = skb_get(skb);
+               adapter->ptp_tx_start = jiffies;
+               schedule_work(&adapter->ptp_tx_work);
        }
 
 #ifdef CONFIG_PCI_IOV
@@ -6453,7 +6449,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
         * Tx switch had been disabled.
         */
        if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
-               tx_flags |= IXGBE_TX_FLAGS_TXSW;
+               tx_flags |= IXGBE_TX_FLAGS_CC;
 
 #endif
        /* DCB maps skb priorities 0-7 onto 3 bit PCP of VLAN tag. */
@@ -6840,6 +6836,26 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
 }
 
 #endif /* CONFIG_IXGBE_DCB */
+#ifdef CONFIG_PCI_IOV
+void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       rtnl_lock();
+#ifdef CONFIG_IXGBE_DCB
+       ixgbe_setup_tc(netdev, netdev_get_num_tc(netdev));
+#else
+       if (netif_running(netdev))
+               ixgbe_close(netdev);
+       ixgbe_clear_interrupt_scheme(adapter);
+       ixgbe_init_interrupt_scheme(adapter);
+       if (netif_running(netdev))
+               ixgbe_open(netdev);
+#endif
+       rtnl_unlock();
+}
+
+#endif
 void ixgbe_do_reset(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -7366,7 +7382,15 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
 #ifdef CONFIG_PCI_IOV
-       ixgbe_enable_sriov(adapter, ii);
+       /* SR-IOV not supported on the 82598 */
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+               goto skip_sriov;
+       /* Mailbox */
+       ixgbe_init_mbx_params_pf(hw);
+       memcpy(&hw->mbx.ops, ii->mbx_ops, sizeof(hw->mbx.ops));
+       ixgbe_enable_sriov(adapter);
+       pci_sriov_set_totalvfs(pdev, 63);
+skip_sriov:
 
 #endif
        netdev->features = NETIF_F_SG |
@@ -7444,9 +7468,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len);
-       memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
 
-       if (!is_valid_ether_addr(netdev->perm_addr)) {
+       if (!is_valid_ether_addr(netdev->dev_addr)) {
                e_dev_err("invalid MAC address\n");
                err = -EIO;
                goto err_sw_init;
@@ -7623,8 +7646,14 @@ static void ixgbe_remove(struct pci_dev *pdev)
        if (netdev->reg_state == NETREG_REGISTERED)
                unregister_netdev(netdev);
 
-       ixgbe_disable_sriov(adapter);
-
+#ifdef CONFIG_PCI_IOV
+       /*
+        * Only disable SR-IOV on unload if the user specified the now
+        * deprecated max_vfs module parameter.
+        */
+       if (max_vfs)
+               ixgbe_disable_sriov(adapter);
+#endif
        ixgbe_clear_interrupt_scheme(adapter);
 
        ixgbe_release_hw_control(adapter);
@@ -7838,6 +7867,7 @@ static struct pci_driver ixgbe_driver = {
        .resume   = ixgbe_resume,
 #endif
        .shutdown = ixgbe_shutdown,
+       .sriov_configure = ixgbe_pci_sriov_configure,
        .err_handler = &ixgbe_err_handler
 };
 
index bb9256a1b0a9b467412ce127911ed3cfb53a7053..53d204759711a52377d3e830c6e939c4fc2c9db1 100644 (file)
 #define IXGBE_MAX_TIMEADJ_VALUE  0x7FFFFFFFFFFFFFFFULL
 
 #define IXGBE_OVERFLOW_PERIOD    (HZ * 30)
+#define IXGBE_PTP_TX_TIMEOUT     (HZ * 15)
 
 #ifndef NSECS_PER_SEC
 #define NSECS_PER_SEC 1000000000ULL
 #endif
 
-static struct sock_filter ptp_filter[] = {
-       PTP_FILTER
-};
-
 /**
  * ixgbe_ptp_setup_sdp
  * @hw: the hardware private structure
@@ -405,149 +402,145 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
        }
 }
 
-
 /**
- * ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow
- * @work: structure containing information about this work task
+ * ixgbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow
+ * @adapter: private adapter struct
  *
- * this work function is scheduled to continue reading the timecounter
+ * this watchdog task periodically reads the timecounter
  * in order to prevent missing when the system time registers wrap
- * around. This needs to be run approximately twice a minute when no
- * PTP activity is occurring.
+ * around. This needs to be run approximately twice a minute.
  */
 void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter)
 {
-       unsigned long elapsed_jiffies = adapter->last_overflow_check - jiffies;
+       bool timeout = time_is_before_jiffies(adapter->last_overflow_check +
+                                            IXGBE_OVERFLOW_PERIOD);
        struct timespec ts;
 
-       if ((adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) &&
-           (elapsed_jiffies >= IXGBE_OVERFLOW_PERIOD)) {
+       if (timeout) {
                ixgbe_ptp_gettime(&adapter->ptp_caps, &ts);
                adapter->last_overflow_check = jiffies;
        }
 }
 
 /**
- * ixgbe_ptp_match - determine if this skb matches a ptp packet
- * @skb: pointer to the skb
- * @hwtstamp: pointer to the hwtstamp_config to check
- *
- * Determine whether the skb should have been timestamped, assuming the
- * hwtstamp was set via the hwtstamp ioctl. Returns non-zero when the packet
- * should have a timestamp waiting in the registers, and 0 otherwise.
+ * ixgbe_ptp_rx_hang - detect error case when Rx timestamp registers latched
+ * @adapter: private network adapter structure
  *
- * V1 packets have to check the version type to determine whether they are
- * correct. However, we can't directly access the data because it might be
- * fragmented in the SKB, in paged memory. In order to work around this, we
- * use skb_copy_bits which will properly copy the data whether it is in the
- * paged memory fragments or not. We have to copy the IP header as well as the
- * message type.
+ * this watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
  */
-static int ixgbe_ptp_match(struct sk_buff *skb, int rx_filter)
+void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter)
 {
-       struct iphdr iph;
-       u8 msgtype;
-       unsigned int type, offset;
-
-       if (rx_filter == HWTSTAMP_FILTER_NONE)
-               return 0;
-
-       type = sk_run_filter(skb, ptp_filter);
-
-       if (likely(rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT))
-               return type & PTP_CLASS_V2;
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbe_ring *rx_ring;
+       u32 tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+       unsigned long rx_event;
+       int n;
 
-       /* For the remaining cases actually check message type */
-       switch (type) {
-       case PTP_CLASS_V1_IPV4:
-               skb_copy_bits(skb, OFF_IHL, &iph, sizeof(iph));
-               offset = ETH_HLEN + (iph.ihl << 2) + UDP_HLEN + OFF_PTP_CONTROL;
-               break;
-       case PTP_CLASS_V1_IPV6:
-               offset = OFF_PTP6 + OFF_PTP_CONTROL;
-               break;
-       default:
-               /* other cases invalid or handled above */
-               return 0;
+       /* if we don't have a valid timestamp in the registers, just update the
+        * timeout counter and exit
+        */
+       if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) {
+               adapter->last_rx_ptp_check = jiffies;
+               return;
        }
 
-       /* Make sure our buffer is long enough */
-       if (skb->len < offset)
-               return 0;
+       /* determine the most recent watchdog or rx_timestamp event */
+       rx_event = adapter->last_rx_ptp_check;
+       for (n = 0; n < adapter->num_rx_queues; n++) {
+               rx_ring = adapter->rx_ring[n];
+               if (time_after(rx_ring->last_rx_timestamp, rx_event))
+                       rx_event = rx_ring->last_rx_timestamp;
+       }
 
-       skb_copy_bits(skb, offset, &msgtype, sizeof(msgtype));
+       /* only need to read the high RXSTMP register to clear the lock */
+       if (time_is_before_jiffies(rx_event + 5*HZ)) {
+               IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
+               adapter->last_rx_ptp_check = jiffies;
 
-       switch (rx_filter) {
-       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
-               return (msgtype == IXGBE_RXMTRL_V1_SYNC_MSG);
-               break;
-       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
-               return (msgtype == IXGBE_RXMTRL_V1_DELAY_REQ_MSG);
-               break;
-       default:
-               return 0;
+               e_warn(drv, "clearing RX Timestamp hang");
        }
 }
 
 /**
  * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
- * @q_vector: structure containing interrupt and ring information
- * @skb: particular skb to send timestamp with
+ * @adapter: the private adapter struct
  *
  * if the timestamp is valid, we convert it into the timecounter ns
  * value, then store that result into the shhwtstamps structure which
  * is passed up the network stack
  */
-void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
-                          struct sk_buff *skb)
+static void ixgbe_ptp_tx_hwtstamp(struct ixgbe_adapter *adapter)
 {
-       struct ixgbe_adapter *adapter;
-       struct ixgbe_hw *hw;
+       struct ixgbe_hw *hw = &adapter->hw;
        struct skb_shared_hwtstamps shhwtstamps;
        u64 regval = 0, ns;
-       u32 tsynctxctl;
        unsigned long flags;
 
-       /* we cannot process timestamps on a ring without a q_vector */
-       if (!q_vector || !q_vector->adapter)
-               return;
-
-       adapter = q_vector->adapter;
-       hw = &adapter->hw;
-
-       tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
        regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL);
        regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32;
 
-       /*
-        * if TX timestamp is not valid, exit after clearing the
-        * timestamp registers
-        */
-       if (!(tsynctxctl & IXGBE_TSYNCTXCTL_VALID))
-               return;
-
        spin_lock_irqsave(&adapter->tmreg_lock, flags);
        ns = timecounter_cyc2time(&adapter->tc, regval);
        spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 
        memset(&shhwtstamps, 0, sizeof(shhwtstamps));
        shhwtstamps.hwtstamp = ns_to_ktime(ns);
-       skb_tstamp_tx(skb, &shhwtstamps);
+       skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
+
+       dev_kfree_skb_any(adapter->ptp_tx_skb);
+       adapter->ptp_tx_skb = NULL;
+}
+
+/**
+ * ixgbe_ptp_tx_hwtstamp_work
+ * @work: pointer to the work struct
+ *
+ * This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware
+ * timestamp has been taken for the current skb. It is necesary, because the
+ * descriptor's "done" bit does not correlate with the timestamp event.
+ */
+static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
+{
+       struct ixgbe_adapter *adapter = container_of(work, struct ixgbe_adapter,
+                                                    ptp_tx_work);
+       struct ixgbe_hw *hw = &adapter->hw;
+       bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
+                                             IXGBE_PTP_TX_TIMEOUT);
+       u32 tsynctxctl;
+
+       /* we have to have a valid skb */
+       if (!adapter->ptp_tx_skb)
+               return;
+
+       if (timeout) {
+               dev_kfree_skb_any(adapter->ptp_tx_skb);
+               adapter->ptp_tx_skb = NULL;
+               e_warn(drv, "clearing Tx Timestamp hang");
+               return;
+       }
+
+       tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
+       if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID)
+               ixgbe_ptp_tx_hwtstamp(adapter);
+       else
+               /* reschedule to keep checking if it's not available yet */
+               schedule_work(&adapter->ptp_tx_work);
 }
 
 /**
- * ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
+ * __ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
  * @q_vector: structure containing interrupt and ring information
- * @rx_desc: the rx descriptor
  * @skb: particular skb to send timestamp with
  *
  * if the timestamp is valid, we convert it into the timecounter ns
  * value, then store that result into the shhwtstamps structure which
  * is passed up the network stack
  */
-void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
-                          union ixgbe_adv_rx_desc *rx_desc,
-                          struct sk_buff *skb)
+void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+                            struct sk_buff *skb)
 {
        struct ixgbe_adapter *adapter;
        struct ixgbe_hw *hw;
@@ -563,37 +556,17 @@ void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
        adapter = q_vector->adapter;
        hw = &adapter->hw;
 
-       if (likely(!ixgbe_ptp_match(skb, adapter->rx_hwtstamp_filter)))
-               return;
-
+       /*
+        * Read the tsyncrxctl register afterwards in order to prevent taking an
+        * I/O hit on every packet.
+        */
        tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
-
-       /* Check if we have a valid timestamp and make sure the skb should
-        * have been timestamped */
        if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID))
                return;
 
-       /*
-        * Always read the registers, in order to clear a possible fault
-        * because of stagnant RX timestamp values for a packet that never
-        * reached the queue.
-        */
        regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
        regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32;
 
-       /*
-        * If the timestamp bit is set in the packet's descriptor, we know the
-        * timestamp belongs to this packet. No other packet can be
-        * timestamped until the registers for timestamping have been read.
-        * Therefor only one packet with this bit can be in the queue at a
-        * time, and the rx timestamp values that were in the registers belong
-        * to this packet.
-        *
-        * If nothing went wrong, then it should have a skb_shared_tx that we
-        * can turn into a skb_shared_hwtstamps.
-        */
-       if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
-               return;
 
        spin_lock_irqsave(&adapter->tmreg_lock, flags);
        ns = timecounter_cyc2time(&adapter->tc, regval);
@@ -698,9 +671,6 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
                return 0;
        }
 
-       /* Store filter value for later use */
-       adapter->rx_hwtstamp_filter = config.rx_filter;
-
        /* define ethertype filter for timestamping L2 packets */
        if (is_l2)
                IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588),
@@ -902,11 +872,8 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
                return;
        }
 
-       /* initialize the ptp filter */
-       if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter)))
-               e_dev_warn("ptp_filter_init failed\n");
-
        spin_lock_init(&adapter->tmreg_lock);
+       INIT_WORK(&adapter->ptp_tx_work, ixgbe_ptp_tx_hwtstamp_work);
 
        adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
                                                &adapter->pdev->dev);
@@ -938,6 +905,12 @@ void ixgbe_ptp_stop(struct ixgbe_adapter *adapter)
 
        ixgbe_ptp_setup_sdp(adapter);
 
+       cancel_work_sync(&adapter->ptp_tx_work);
+       if (adapter->ptp_tx_skb) {
+               dev_kfree_skb_any(adapter->ptp_tx_skb);
+               adapter->ptp_tx_skb = NULL;
+       }
+
        if (adapter->ptp_clock) {
                ptp_clock_unregister(adapter->ptp_clock);
                adapter->ptp_clock = NULL;
index 85cddac673ef41716d9a34f027b1bcbb0cfb903d..ee3507f0ea530c309475c9799f2b2067e998501f 100644 (file)
 #include "ixgbe_sriov.h"
 
 #ifdef CONFIG_PCI_IOV
-void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
-                        const struct ixgbe_info *ii)
+static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        int num_vf_macvlans, i;
        struct vf_macvlans *mv_list;
-       int pre_existing_vfs = 0;
-
-       pre_existing_vfs = pci_num_vf(adapter->pdev);
-       if (!pre_existing_vfs && !adapter->num_vfs)
-               return;
-
-       /* If there are pre-existing VFs then we have to force
-        * use of that many because they were not deleted the last
-        * time someone removed the PF driver.  That would have
-        * been because they were allocated to guest VMs and can't
-        * be removed.  Go ahead and just re-enable the old amount.
-        * If the user wants to change the number of VFs they can
-        * use ethtool while making sure no VFs are allocated to
-        * guest VMs... i.e. the right way.
-        */
-       if (pre_existing_vfs) {
-               adapter->num_vfs = pre_existing_vfs;
-               dev_warn(&adapter->pdev->dev, "Virtual Functions already "
-                        "enabled for this device - Please reload all "
-                        "VF drivers to avoid spoofed packet errors\n");
-       } else {
-               int err;
-               /*
-                * The 82599 supports up to 64 VFs per physical function
-                * but this implementation limits allocation to 63 so that
-                * basic networking resources are still available to the
-                * physical function.  If the user requests greater thn
-                * 63 VFs then it is an error - reset to default of zero.
-                */
-               adapter->num_vfs = min_t(unsigned int, adapter->num_vfs, 63);
-
-               err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
-               if (err) {
-                       e_err(probe, "Failed to enable PCI sriov: %d\n", err);
-                       adapter->num_vfs = 0;
-                       return;
-               }
-       }
 
        adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
        e_info(probe, "SR-IOV enabled with %d VFs\n", adapter->num_vfs);
@@ -128,12 +89,6 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
                kcalloc(adapter->num_vfs,
                        sizeof(struct vf_data_storage), GFP_KERNEL);
        if (adapter->vfinfo) {
-               /* Now that we're sure SR-IOV is enabled
-                * and memory allocated set up the mailbox parameters
-                */
-               ixgbe_init_mbx_params_pf(hw);
-               memcpy(&hw->mbx.ops, ii->mbx_ops, sizeof(hw->mbx.ops));
-
                /* limit trafffic classes based on VFs enabled */
                if ((adapter->hw.mac.type == ixgbe_mac_82599EB) &&
                    (adapter->num_vfs < 16)) {
@@ -157,10 +112,62 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
                /* enable spoof checking for all VFs */
                for (i = 0; i < adapter->num_vfs; i++)
                        adapter->vfinfo[i].spoofchk_enabled = true;
+               return 0;
+       }
+
+       return -ENOMEM;
+}
+
+/* Note this function is called when the user wants to enable SR-IOV
+ * VFs using the now deprecated module parameter
+ */
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
+{
+       int pre_existing_vfs = 0;
+
+       pre_existing_vfs = pci_num_vf(adapter->pdev);
+       if (!pre_existing_vfs && !adapter->num_vfs)
                return;
+
+       if (!pre_existing_vfs)
+               dev_warn(&adapter->pdev->dev,
+                        "Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
+
+       /* If there are pre-existing VFs then we have to force
+        * use of that many - over ride any module parameter value.
+        * This may result from the user unloading the PF driver
+        * while VFs were assigned to guest VMs or because the VFs
+        * have been created via the new PCI SR-IOV sysfs interface.
+        */
+       if (pre_existing_vfs) {
+               adapter->num_vfs = pre_existing_vfs;
+               dev_warn(&adapter->pdev->dev,
+                        "Virtual Functions already enabled for this device - Please reload all VF drivers to avoid spoofed packet errors\n");
+       } else {
+               int err;
+               /*
+                * The 82599 supports up to 64 VFs per physical function
+                * but this implementation limits allocation to 63 so that
+                * basic networking resources are still available to the
+                * physical function.  If the user requests greater thn
+                * 63 VFs then it is an error - reset to default of zero.
+                */
+               adapter->num_vfs = min_t(unsigned int, adapter->num_vfs, 63);
+
+               err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+               if (err) {
+                       e_err(probe, "Failed to enable PCI sriov: %d\n", err);
+                       adapter->num_vfs = 0;
+                       return;
+               }
        }
 
-       /* Oh oh */
+       if (!__ixgbe_enable_sriov(adapter))
+               return;
+
+       /* If we have gotten to this point then there is no memory available
+        * to manage the VF devices - print message and bail.
+        */
        e_err(probe, "Unable to allocate memory for VF Data Storage - "
              "SRIOV disabled\n");
        ixgbe_disable_sriov(adapter);
@@ -200,11 +207,12 @@ static bool ixgbe_vfs_are_assigned(struct ixgbe_adapter *adapter)
 }
 
 #endif /* #ifdef CONFIG_PCI_IOV */
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
+int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        u32 gpie;
        u32 vmdctl;
+       int rss;
 
        /* set num VFs to 0 to prevent access to vfinfo */
        adapter->num_vfs = 0;
@@ -219,7 +227,7 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 
        /* if SR-IOV is already disabled then there is nothing to do */
        if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
-               return;
+               return 0;
 
 #ifdef CONFIG_PCI_IOV
        /*
@@ -229,7 +237,7 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
         */
        if (ixgbe_vfs_are_assigned(adapter)) {
                e_dev_warn("Unloading driver while VFs are assigned - VFs will not be deallocated\n");
-               return;
+               return -EPERM;
        }
        /* disable iov and allow time for transactions to clear */
        pci_disable_sriov(adapter->pdev);
@@ -252,10 +260,94 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
                adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
        adapter->ring_feature[RING_F_VMDQ].offset = 0;
 
+       rss = min_t(int, IXGBE_MAX_RSS_INDICES, num_online_cpus());
+       adapter->ring_feature[RING_F_RSS].limit = rss;
+
        /* take a breather then clean up driver data */
        msleep(100);
 
        adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+       return 0;
+}
+
+static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+       struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+       int err = 0;
+       int i;
+       int pre_existing_vfs = pci_num_vf(dev);
+
+       if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+               err = ixgbe_disable_sriov(adapter);
+       else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+               goto out;
+
+       if (err)
+               goto err_out;
+
+       /* While the SR-IOV capability structure reports total VFs to be
+        * 64 we limit the actual number that can be allocated to 63 so
+        * that some transmit/receive resources can be reserved to the
+        * PF.  The PCI bus driver already checks for other values out of
+        * range.
+        */
+       if (num_vfs > 63) {
+               err = -EPERM;
+               goto err_out;
+       }
+
+       adapter->num_vfs = num_vfs;
+
+       err = __ixgbe_enable_sriov(adapter);
+       if (err)
+               goto err_out;
+
+       for (i = 0; i < adapter->num_vfs; i++)
+               ixgbe_vf_configuration(dev, (i | 0x10000000));
+
+       err = pci_enable_sriov(dev, num_vfs);
+       if (err) {
+               e_dev_warn("Failed to enable PCI sriov: %d\n", err);
+               goto err_out;
+       }
+       ixgbe_sriov_reinit(adapter);
+
+out:
+       return num_vfs;
+
+err_out:
+       return err;
+#endif
+       return 0;
+}
+
+static int ixgbe_pci_sriov_disable(struct pci_dev *dev)
+{
+       struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+       int err;
+       u32 current_flags = adapter->flags;
+
+       err = ixgbe_disable_sriov(adapter);
+
+       /* Only reinit if no error and state changed */
+       if (!err && current_flags != adapter->flags) {
+               /* ixgbe_disable_sriov() doesn't clear VMDQ flag */
+               adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
+#ifdef CONFIG_PCI_IOV
+               ixgbe_sriov_reinit(adapter);
+#endif
+       }
+
+       return err;
+}
+
+int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+       if (num_vfs == 0)
+               return ixgbe_pci_sriov_disable(dev);
+       else
+               return ixgbe_pci_sriov_enable(dev, num_vfs);
 }
 
 static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
@@ -447,15 +539,6 @@ static void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
        IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
 }
 
-static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter,
-                           u16 vid, u16 qos, u32 vf)
-{
-       struct ixgbe_hw *hw = &adapter->hw;
-       u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) | IXGBE_VMVIR_VLANA_DEFAULT;
-
-       IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), vmvir);
-}
-
 static void ixgbe_clear_vmvir(struct ixgbe_adapter *adapter, u32 vf)
 {
        struct ixgbe_hw *hw = &adapter->hw;
index 1be1d30e4e78e15aef20d281aa9a2ca7066ca301..008f9cea68d118074a05418e025cef4a177b0a81 100644 (file)
@@ -41,12 +41,20 @@ int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
 int ixgbe_ndo_get_vf_config(struct net_device *netdev,
                            int vf, struct ifla_vf_info *ivi);
 void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter);
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
+int ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
 #ifdef CONFIG_PCI_IOV
-void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
-                       const struct ixgbe_info *ii);
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter);
 #endif
+int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
 
+static inline void ixgbe_set_vmvir(struct ixgbe_adapter *adapter,
+                                  u16 vid, u16 qos, u32 vf)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) | IXGBE_VMVIR_VLANA_DEFAULT;
+
+       IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), vmvir);
+}
 
 #endif /* _IXGBE_SRIOV_H_ */
 
index 8f2070439b5966fdc515eef68f07ebbda4ef1bba..c9d0c12d6f04156e19ec0240c19d64c0f23ebc8a 100644 (file)
@@ -99,6 +99,7 @@ static int ixgbevf_get_settings(struct net_device *netdev,
        ecmd->transceiver = XCVR_DUMMY1;
        ecmd->port = -1;
 
+       hw->mac.get_link_status = 1;
        hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
 
        if (link_up) {
index 257357ae66c365169d6130306d9180789965c98e..c3db6cd69b68b0135f42908fd738bd7c9fd4fddc 100644 (file)
@@ -750,12 +750,37 @@ static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector)
 static irqreturn_t ixgbevf_msix_other(int irq, void *data)
 {
        struct ixgbevf_adapter *adapter = data;
+       struct pci_dev *pdev = adapter->pdev;
        struct ixgbe_hw *hw = &adapter->hw;
+       u32 msg;
+       bool got_ack = false;
 
        hw->mac.get_link_status = 1;
+       if (!hw->mbx.ops.check_for_ack(hw))
+               got_ack = true;
 
-       if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
-               mod_timer(&adapter->watchdog_timer, jiffies);
+       if (!hw->mbx.ops.check_for_msg(hw)) {
+               hw->mbx.ops.read(hw, &msg, 1);
+
+               if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) {
+                       mod_timer(&adapter->watchdog_timer,
+                                 round_jiffies(jiffies + 1));
+                       adapter->link_up = false;
+               }
+
+               if (msg & IXGBE_VT_MSGTYPE_NACK)
+                       dev_info(&pdev->dev,
+                                "Last Request of type %2.2x to PF Nacked\n",
+                                msg & 0xFF);
+               hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFSTS;
+       }
+
+       /* checking for the ack clears the PFACK bit.  Place
+        * it back in the v2p_mailbox cache so that anyone
+        * polling for an ack will not miss it
+        */
+       if (got_ack)
+               hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFACK;
 
        IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other);
 
@@ -2095,6 +2120,9 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
        struct ixgbe_hw *hw = &adapter->hw;
        int i;
 
+       if (!adapter->link_up)
+               return;
+
        UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc,
                                adapter->stats.vfgprc);
        UPDATE_VF_COUNTER_32bit(IXGBE_VFGPTC, adapter->stats.last_vfgptc,
@@ -2217,9 +2245,23 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
 
        if (link_up) {
                if (!netif_carrier_ok(netdev)) {
-                       hw_dbg(&adapter->hw, "NIC Link is Up, %u Gbps\n",
-                              (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
-                              10 : 1);
+                       char *link_speed_string;
+                       switch (link_speed) {
+                       case IXGBE_LINK_SPEED_10GB_FULL:
+                               link_speed_string = "10 Gbps";
+                               break;
+                       case IXGBE_LINK_SPEED_1GB_FULL:
+                               link_speed_string = "1 Gbps";
+                               break;
+                       case IXGBE_LINK_SPEED_100_FULL:
+                               link_speed_string = "100 Mbps";
+                               break;
+                       default:
+                               link_speed_string = "unknown speed";
+                               break;
+                       }
+                       dev_info(&adapter->pdev->dev,
+                               "NIC Link is Up, %s\n", link_speed_string);
                        netif_carrier_on(netdev);
                        netif_tx_wake_all_queues(netdev);
                }
@@ -2227,7 +2269,7 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
                adapter->link_up = false;
                adapter->link_speed = 0;
                if (netif_carrier_ok(netdev)) {
-                       hw_dbg(&adapter->hw, "NIC Link is Down\n");
+                       dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
                        netif_carrier_off(netdev);
                        netif_tx_stop_all_queues(netdev);
                }
@@ -3328,8 +3370,6 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_sw_init;
 
        /* The HW MAC address was set and/or determined in sw_init */
-       memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
-
        if (!is_valid_ether_addr(netdev->dev_addr)) {
                pr_err("invalid MAC address\n");
                err = -EIO;
index bc58f1dc22f50f204e7ec46045052999b0437d92..5409fe876a441607488d43ac39829f7e5fc9e891 100644 (file)
@@ -695,9 +695,9 @@ static void netdev_get_drvinfo(struct net_device *dev,
 {
        struct korina_private *lp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, lp->dev->name);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, lp->dev->name, sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index c124e67a1a1ca72599d8fe81f449f32f69480f4f..6a2127489af78e718264f202737ba0667770ba1b 100644 (file)
@@ -302,9 +302,9 @@ ltq_etop_hw_init(struct net_device *dev)
 static void
 ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "Lantiq ETOP");
-       strcpy(info->bus_info, "internal");
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, "Lantiq ETOP", sizeof(info->driver));
+       strlcpy(info->bus_info, "internal", sizeof(info->bus_info));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int
@@ -393,8 +393,8 @@ ltq_etop_mdio_probe(struct net_device *dev)
                return -ENODEV;
        }
 
-       phydev = phy_connect(dev, dev_name(&phydev->dev), &ltq_etop_mdio_link,
-                       0, priv->pldata->mii_mode);
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
+                            &ltq_etop_mdio_link, priv->pldata->mii_mode);
 
        if (IS_ERR(phydev)) {
                netdev_err(dev, "Could not attach to PHY\n");
@@ -655,7 +655,7 @@ ltq_etop_init(struct net_device *dev)
 
        /* Set addr_assign_type here, ltq_etop_set_mac_address would reset it. */
        if (random_mac)
-               dev->addr_assign_type |= NET_ADDR_RANDOM;
+               dev->addr_assign_type = NET_ADDR_RANDOM;
 
        ltq_etop_set_multicast_list(dev);
        err = ltq_etop_mdio_init(dev);
index 84c13263c514c988e44d4335d3ccae0147c220d6..c27b23d8f4fc29bee16017ed29eda6ea3bc09507 100644 (file)
@@ -2789,7 +2789,7 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)
 
        phy_reset(mp);
 
-       phy_attach(mp->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_GMII);
+       phy_attach(mp->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_GMII);
 
        if (speed == 0) {
                phy->autoneg = AUTONEG_ENABLE;
index 10d678d3dd018bf40d4ca857459de4c81cd438d6..037ed866c22ffa7cfdd57b54fb45216a0a3dd729 100644 (file)
@@ -627,7 +627,6 @@ static int pxa168_eth_set_mac_address(struct net_device *dev, void *addr)
        if (!is_valid_ether_addr(sa->sa_data))
                return -EADDRNOTAVAIL;
        memcpy(oldMac, dev->dev_addr, ETH_ALEN);
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
        netif_addr_lock_bh(dev);
        update_hash_table_mac_address(pep, oldMac, dev->dev_addr);
@@ -1391,7 +1390,7 @@ static void phy_init(struct pxa168_eth_private *pep, int speed, int duplex)
        struct phy_device *phy = pep->phy;
        ethernet_phy_reset(pep);
 
-       phy_attach(pep->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_MII);
+       phy_attach(pep->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_MII);
 
        if (speed == 0) {
                phy->autoneg = AUTONEG_ENABLE;
@@ -1444,10 +1443,10 @@ static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void pxa168_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, DRIVER_NAME, 32);
-       strncpy(info->version, DRIVER_VERSION, 32);
-       strncpy(info->fw_version, "N/A", 32);
-       strncpy(info->bus_info, "N/A", 32);
+       strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops pxa168_ethtool_ops = {
index 5544a1fe2f948f5e64ab2c38e00df0aa82255efa..8b08bc4b8a76a747401e05044fc18fac380f040c 100644 (file)
@@ -3855,7 +3855,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
 
        /* read the mac address */
        memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        return dev;
 }
index 3269eb38cc576924a958354b9e664b1a92b26dd2..366a12aa3c74336c51affd951963194ec3ebe713 100644 (file)
@@ -4801,7 +4801,6 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
 
        /* read the mac address */
        memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        return dev;
 }
index 75a3f467bb5be601494653a8406eaf5780e52d5b..9c42812d2f6b79472374059e634922206f7bf9fa 100644 (file)
@@ -767,9 +767,9 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 
                /* Update multicast list - we cache all addresses so they won't
                 * change while HW is updated holding the command semaphor */
-               netif_tx_lock_bh(dev);
+               netif_addr_lock_bh(dev);
                mlx4_en_cache_mclist(dev);
-               netif_tx_unlock_bh(dev);
+               netif_addr_unlock_bh(dev);
                list_for_each_entry(mclist, &priv->mc_list, list) {
                        mcast_addr = mlx4_en_mac_to_u64(mclist->addr);
                        mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
@@ -977,12 +977,12 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
        struct mlx4_en_dev *mdev = priv->mdev;
        int err;
 
-       err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
-       if (err)
-               en_dbg(HW, priv, "Could not update stats\n");
-
        mutex_lock(&mdev->state_lock);
        if (mdev->device_up) {
+               err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
+               if (err)
+                       en_dbg(HW, priv, "Could not update stats\n");
+
                if (priv->port_up)
                        mlx4_en_auto_moderation(priv);
 
@@ -1167,15 +1167,6 @@ int mlx4_en_start_port(struct net_device *dev)
 
        /* Must redo promiscuous mode setup. */
        priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC);
-       if (mdev->dev->caps.steering_mode ==
-           MLX4_STEERING_MODE_DEVICE_MANAGED) {
-               mlx4_flow_steer_promisc_remove(mdev->dev,
-                                              priv->port,
-                                              MLX4_FS_PROMISC_UPLINK);
-               mlx4_flow_steer_promisc_remove(mdev->dev,
-                                              priv->port,
-                                              MLX4_FS_PROMISC_ALL_MULTI);
-       }
 
        /* Schedule multicast task to populate multicast list */
        queue_work(mdev->workqueue, &priv->mcast_task);
@@ -1227,6 +1218,32 @@ void mlx4_en_stop_port(struct net_device *dev)
        /* Set port as not active */
        priv->port_up = false;
 
+       /* Promsicuous mode */
+       if (mdev->dev->caps.steering_mode ==
+           MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               priv->flags &= ~(MLX4_EN_FLAG_PROMISC |
+                                MLX4_EN_FLAG_MC_PROMISC);
+               mlx4_flow_steer_promisc_remove(mdev->dev,
+                                              priv->port,
+                                              MLX4_FS_PROMISC_UPLINK);
+               mlx4_flow_steer_promisc_remove(mdev->dev,
+                                              priv->port,
+                                              MLX4_FS_PROMISC_ALL_MULTI);
+       } else if (priv->flags & MLX4_EN_FLAG_PROMISC) {
+               priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+
+               /* Disable promiscouos mode */
+               mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn,
+                                           priv->port);
+
+               /* Disable Multicast promisc */
+               if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+                       mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
+                                                     priv->port);
+                       priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+               }
+       }
+
        /* Detach All multicasts */
        memset(&mc_list[10], 0xff, ETH_ALEN);
        mc_list[5] = priv->port; /* needed for B0 steering support */
@@ -1437,9 +1454,6 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
        priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->rx_ring_num);
        if (!priv->dev->rx_cpu_rmap)
                goto err;
-
-       INIT_LIST_HEAD(&priv->filters);
-       spin_lock_init(&priv->filters_lock);
 #endif
 
        return 0;
@@ -1634,6 +1648,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        if (err)
                goto out;
 
+#ifdef CONFIG_RFS_ACCEL
+       INIT_LIST_HEAD(&priv->filters);
+       spin_lock_init(&priv->filters_lock);
+#endif
+
        /* Allocate page for receive rings */
        err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
                                MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
@@ -1655,10 +1674,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 
        /* Set defualt MAC */
        dev->addr_len = ETH_ALEN;
-       for (i = 0; i < ETH_ALEN; i++) {
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
-               dev->perm_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
-       }
 
        /*
         * Set driver features
index 6771b69f40d562bf58909a1f806bddd1ace9ea65..30724d811115717ec1a39bcc93a726be5e593d82 100644 (file)
@@ -515,10 +515,6 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
                wmb();
                inl->byte_count = cpu_to_be32(1 << 31 | (skb->len - spc));
        }
-       tx_desc->ctrl.vlan_tag = cpu_to_be16(*vlan_tag);
-       tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN *
-               (!!vlan_tx_tag_present(skb));
-       tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
 }
 
 u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
@@ -592,7 +588,21 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_tx_stop_queue(ring->tx_queue);
                priv->port_stats.queue_stopped++;
 
-               return NETDEV_TX_BUSY;
+               /* If queue was emptied after the if, and before the
+                * stop_queue - need to wake the queue, or else it will remain
+                * stopped forever.
+                * Need a memory barrier to make sure ring->cons was not
+                * updated before queue was stopped.
+                */
+               wmb();
+
+               if (unlikely(((int)(ring->prod - ring->cons)) <=
+                            ring->size - HEADROOM - MAX_DESC_TXBBS)) {
+                       netif_tx_wake_queue(ring->tx_queue);
+                       priv->port_stats.wake_queue++;
+               } else {
+                       return NETDEV_TX_BUSY;
+               }
        }
 
        /* Track current inflight packets for performance analysis */
index a6542d75374cdce3f7a17c21f7022fadff109850..f1ee52d10467b4a6a48e393b70f81f27bc595fde 100644 (file)
@@ -2162,7 +2162,8 @@ slave_start:
                        dev->num_slaves = MLX4_MAX_NUM_SLAVES;
                else {
                        dev->num_slaves = 0;
-                       if (mlx4_multi_func_init(dev)) {
+                       err = mlx4_multi_func_init(dev);
+                       if (err) {
                                mlx4_err(dev, "Failed to init slave mfunc"
                                         " interface, aborting.\n");
                                goto err_cmd;
@@ -2186,7 +2187,8 @@ slave_start:
        /* In master functions, the communication channel must be initialized
         * after obtaining its address from fw */
        if (mlx4_is_master(dev)) {
-               if (mlx4_multi_func_init(dev)) {
+               err = mlx4_multi_func_init(dev);
+               if (err) {
                        mlx4_err(dev, "Failed to init master mfunc"
                                 "interface, aborting.\n");
                        goto err_close;
@@ -2203,6 +2205,7 @@ slave_start:
        mlx4_enable_msi_x(dev);
        if ((mlx4_is_mfunc(dev)) &&
            !(dev->flags & MLX4_FLAG_MSI_X)) {
+               err = -ENOSYS;
                mlx4_err(dev, "INTx is not supported in multi-function mode."
                         " aborting.\n");
                goto err_free_eq;
index b71eb39ab4483e6d6bd7021d42bdf620f0977a9d..fbcb9e74d7fc598f1fe52951a087603f58e11efc 100644 (file)
@@ -1080,7 +1080,6 @@ static int ks8842_set_mac(struct net_device *netdev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(netdev->dev_addr, mac, netdev->addr_len);
 
        ks8842_write_mac_addr(adapter, mac);
index 286816a4e7833c27e2e994a400be44f968c4c354..33bcb63d56a2355c93dbd1306f24bce816eab23c 100644 (file)
@@ -69,7 +69,6 @@ union ks8851_tx_hdr {
  * @mii: The MII state information for the mii calls.
  * @rxctrl: RX settings for @rxctrl_work.
  * @tx_work: Work queue for tx packets
- * @irq_work: Work queue for servicing interrupts
  * @rxctrl_work: Work queue for updating RX mode and multicast lists
  * @txq: Queue of packets for transmission.
  * @spi_msg1: pre-setup SPI transfer with one message, @spi_xfer1.
@@ -121,7 +120,6 @@ struct ks8851_net {
        struct ks8851_rxctrl    rxctrl;
 
        struct work_struct      tx_work;
-       struct work_struct      irq_work;
        struct work_struct      rxctrl_work;
 
        struct sk_buff_head     txq;
@@ -443,23 +441,6 @@ static void ks8851_init_mac(struct ks8851_net *ks)
        ks8851_write_mac_addr(dev);
 }
 
-/**
- * ks8851_irq - device interrupt handler
- * @irq: Interrupt number passed from the IRQ handler.
- * @pw: The private word passed to register_irq(), our struct ks8851_net.
- *
- * Disable the interrupt from happening again until we've processed the
- * current status by scheduling ks8851_irq_work().
- */
-static irqreturn_t ks8851_irq(int irq, void *pw)
-{
-       struct ks8851_net *ks = pw;
-
-       disable_irq_nosync(irq);
-       schedule_work(&ks->irq_work);
-       return IRQ_HANDLED;
-}
-
 /**
  * ks8851_rdfifo - read data from the receive fifo
  * @ks: The device state.
@@ -595,19 +576,20 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)
 }
 
 /**
- * ks8851_irq_work - work queue handler for dealing with interrupt requests
- * @work: The work structure that was scheduled by schedule_work()
+ * ks8851_irq - IRQ handler for dealing with interrupt requests
+ * @irq: IRQ number
+ * @_ks: cookie
  *
- * This is the handler invoked when the ks8851_irq() is called to find out
- * what happened, as we cannot allow ourselves to sleep whilst waiting for
- * anything other process has the chip's lock.
+ * This handler is invoked when the IRQ line asserts to find out what happened.
+ * As we cannot allow ourselves to sleep in HARDIRQ context, this handler runs
+ * in thread context.
  *
  * Read the interrupt status, work out what needs to be done and then clear
  * any of the interrupts that are not needed.
  */
-static void ks8851_irq_work(struct work_struct *work)
+static irqreturn_t ks8851_irq(int irq, void *_ks)
 {
-       struct ks8851_net *ks = container_of(work, struct ks8851_net, irq_work);
+       struct ks8851_net *ks = _ks;
        unsigned status;
        unsigned handled = 0;
 
@@ -688,7 +670,7 @@ static void ks8851_irq_work(struct work_struct *work)
        if (status & IRQ_TXI)
                netif_wake_queue(ks->netdev);
 
-       enable_irq(ks->netdev->irq);
+       return IRQ_HANDLED;
 }
 
 /**
@@ -896,7 +878,6 @@ static int ks8851_net_stop(struct net_device *dev)
        mutex_unlock(&ks->lock);
 
        /* stop any outstanding work */
-       flush_work(&ks->irq_work);
        flush_work(&ks->tx_work);
        flush_work(&ks->rxctrl_work);
 
@@ -1052,7 +1033,6 @@ static int ks8851_set_mac_address(struct net_device *dev, void *addr)
        if (!is_valid_ether_addr(sa->sa_data))
                return -EADDRNOTAVAIL;
 
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
        return ks8851_write_mac_addr(dev);
 }
@@ -1438,7 +1418,6 @@ static int ks8851_probe(struct spi_device *spi)
        spin_lock_init(&ks->statelock);
 
        INIT_WORK(&ks->tx_work, ks8851_tx_work);
-       INIT_WORK(&ks->irq_work, ks8851_irq_work);
        INIT_WORK(&ks->rxctrl_work, ks8851_rxctrl_work);
 
        /* initialise pre-made spi transfer messages */
@@ -1505,8 +1484,9 @@ static int ks8851_probe(struct spi_device *spi)
        ks8851_read_selftest(ks);
        ks8851_init_mac(ks);
 
-       ret = request_irq(spi->irq, ks8851_irq, IRQF_TRIGGER_LOW,
-                         ndev->name, ks);
+       ret = request_threaded_irq(spi->irq, NULL, ks8851_irq,
+                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                  ndev->name, ks);
        if (ret < 0) {
                dev_err(&spi->dev, "failed to get irq\n");
                goto err_irq;
index ef8f9f92e5476daf73be7e7e3bbbb774695260af..a343066f7b436d1526b0c9a58fe3beb67131c6ea 100644 (file)
@@ -1237,7 +1237,6 @@ static int ks_set_mac_address(struct net_device *netdev, void *paddr)
        struct sockaddr *addr = paddr;
        u8 *da;
 
-       netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
        da = (u8 *)netdev->dev_addr;
index a99456c3dd872a783578e7f78c7a3ff4cb316fad..5d98a9f7bfc7071b63b9796ec59166b9027972b0 100644 (file)
@@ -527,7 +527,6 @@ static int enc28j60_set_mac_address(struct net_device *dev, void *addr)
        if (!is_valid_ether_addr(address->sa_data))
                return -EADDRNOTAVAIL;
 
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
        return enc28j60_set_hw_macaddr(dev);
 }
diff --git a/drivers/net/ethernet/natsemi/ibmlana.c b/drivers/net/ethernet/natsemi/ibmlana.c
deleted file mode 100644 (file)
index 923e640..0000000
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
-net-3-driver for the IBM LAN Adapter/A
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
-                                 alfred.arnold@lancom.de)
-
-This driver is based both on the SK_MCA driver, which is itself based on the
-SK_G16 and 3C523 driver.
-
-paper sources:
-  'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
-  Hans-Peter Messmer for the basic Microchannel stuff
-
-  'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
-  for help on Ethernet driver programming
-
-  'DP83934CVUL-20/25 MHz SONIC-T Ethernet Controller Datasheet' by National
-  Semiconductor for info on the MAC chip
-
-  'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0
-   Document Number SC30-3661-00' by IBM for info on the adapter itself
-
-  Also see http://www.national.com/analog 
-
-special acknowledgements to:
-  - Bob Eager for helping me out with documentation from IBM
-  - Jim Shorney for his endless patience with me while I was using
-    him as a beta tester to trace down the address filter bug ;-)
-
-  Missing things:
-
-  -> set debug level via ioctl instead of compile-time switches
-  -> I didn't follow the development of the 2.1.x kernels, so my
-     assumptions about which things changed with which kernel version
-     are probably nonsense
-
-History:
-  Nov 6th, 1999
-       startup from SK_MCA driver
-  Dec 6th, 1999
-       finally got docs about the card.  A big thank you to Bob Eager!
-  Dec 12th, 1999
-       first packet received
-  Dec 13th, 1999
-       recv queue done, tcpdump works
-  Dec 15th, 1999
-       transmission part works
-  Dec 28th, 1999
-       added usage of the isa_functions for Linux 2.3 .  Things should
-       still work with 2.0.x....
-  Jan 28th, 2000
-       in Linux 2.2.13, the version.h file mysteriously didn't get
-       included.  Added a workaround for this.  Furthermore, it now
-       not only compiles as a modules ;-)
-  Jan 30th, 2000
-       newer kernels automatically probe more than one board, so the
-       'startslot' as a variable is also needed here
-  Apr 12th, 2000
-       the interrupt mask register is not set 'hard' instead of individually
-       setting registers, since this seems to set bits that shouldn't be
-       set
-  May 21st, 2000
-       reset interrupt status immediately after CAM load
-       add a recovery delay after releasing the chip's reset line
-  May 24th, 2000
-       finally found the bug in the address filter setup - damned signed
-        chars!
-  June 1st, 2000
-       corrected version codes, added support for the latest 2.3 changes
-  Oct 28th, 2002
-       cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk>
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _IBM_LANA_DRIVER_
-#include "ibmlana.h"
-
-#undef DEBUG
-
-#define DRV_NAME "ibmlana"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] = {
-       "10BaseT", "10Base5", "Unknown", "10Base2"
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-#ifdef DEBUG
-  /* dump all registers */
-
-static void dumpregs(struct net_device *dev)
-{
-       int z;
-
-       for (z = 0; z < 160; z += 2) {
-               if (!(z & 15))
-                       printk("REGS: %04x:", z);
-               printk(" %04x", inw(dev->base_addr + z));
-               if ((z & 15) == 14)
-                       printk("\n");
-       }
-}
-
-/* dump parts of shared memory - only needed during debugging */
-
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       int z;
-
-       printk("Address %04x:\n", start);
-       for (z = 0; z < len; z++) {
-               if ((z & 15) == 0)
-                       printk("%04x:", z);
-               printk(" %02x", readb(priv->base + start + z));
-               if ((z & 15) == 15)
-                       printk("\n");
-       }
-       if ((z & 15) != 0)
-               printk("\n");
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
-       struct timeval tv;
-
-       do_gettimeofday(&tv);
-       printk("%9d:%06d: ", (int) tv.tv_sec, (int) tv.tv_usec);
-}
-#endif                         /* DEBUG */
-
-/* deduce resources out of POS registers */
-
-static void getaddrs(struct mca_device *mdev, int *base, int *memlen,
-                    int *iobase, int *irq, ibmlana_medium *medium)
-{
-       u_char pos0, pos1;
-
-       pos0 = mca_device_read_stored_pos(mdev, 2);
-       pos1 = mca_device_read_stored_pos(mdev, 3);
-
-       *base = 0xc0000 + ((pos1 & 0xf0) << 9);
-       *memlen = (pos1 & 0x01) ? 0x8000 : 0x4000;
-       *iobase = (pos0 & 0xe0) << 7;
-       switch (pos0 & 0x06) {
-       case 0:
-               *irq = 5;
-               break;
-       case 2:
-               *irq = 15;
-               break;
-       case 4:
-               *irq = 10;
-               break;
-       case 6:
-               *irq = 11;
-               break;
-       }
-       *medium = (pos0 & 0x18) >> 3;
-}
-
-/* wait on register value with mask and timeout */
-
-static int wait_timeout(struct net_device *dev, int regoffs, u16 mask,
-                       u16 value, int timeout)
-{
-       unsigned long fin = jiffies + timeout;
-
-       while (time_before(jiffies,fin))
-               if ((inw(dev->base_addr + regoffs) & mask) == value)
-                       return 1;
-
-       return 0;
-}
-
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
-       unsigned char bcmval;
-
-       /* read original board control value */
-
-       bcmval = inb(dev->base_addr + BCMREG);
-
-       /* set reset bit for a while */
-
-       bcmval |= BCMREG_RESET;
-       outb(bcmval, dev->base_addr + BCMREG);
-       udelay(10);
-       bcmval &= ~BCMREG_RESET;
-       outb(bcmval, dev->base_addr + BCMREG);
-
-       /* switch over to RAM again */
-
-       bcmval |= BCMREG_RAMEN | BCMREG_RAMWIN;
-       outb(bcmval, dev->base_addr + BCMREG);
-}
-
-/* calculate RAM layout & set up descriptors in RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       u32 addr, baddr, raddr;
-       int z;
-       tda_t tda;
-       rda_t rda;
-       rra_t rra;
-
-       /* initialize RAM */
-
-       memset_io(priv->base, 0xaa,
-                     dev->mem_start - dev->mem_start); /* XXX: typo? */
-
-       /* setup n TX descriptors - independent of RAM size */
-
-       priv->tdastart = addr = 0;
-       priv->txbufstart = baddr = sizeof(tda_t) * TXBUFCNT;
-       for (z = 0; z < TXBUFCNT; z++) {
-               tda.status = 0;
-               tda.config = 0;
-               tda.length = 0;
-               tda.fragcount = 1;
-               tda.startlo = baddr;
-               tda.starthi = 0;
-               tda.fraglength = 0;
-               if (z == TXBUFCNT - 1)
-                       tda.link = priv->tdastart;
-               else
-                       tda.link = addr + sizeof(tda_t);
-               tda.link |= 1;
-               memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
-               addr += sizeof(tda_t);
-               baddr += PKTSIZE;
-       }
-
-       /* calculate how many receive buffers fit into remaining memory */
-
-       priv->rxbufcnt = (dev->mem_end - dev->mem_start - baddr) / (sizeof(rra_t) + sizeof(rda_t) + PKTSIZE);
-
-       /* calculate receive addresses */
-
-       priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE);
-       priv->rdastart = addr = priv->rrastart + (priv->rxbufcnt * sizeof(rra_t));
-       priv->rxbufstart = baddr = priv->rdastart + (priv->rxbufcnt * sizeof(rda_t));
-
-       for (z = 0; z < priv->rxbufcnt; z++) {
-               rra.startlo = baddr;
-               rra.starthi = 0;
-               rra.cntlo = PKTSIZE >> 1;
-               rra.cnthi = 0;
-               memcpy_toio(priv->base + raddr, &rra, sizeof(rra_t));
-
-               rda.status = 0;
-               rda.length = 0;
-               rda.startlo = 0;
-               rda.starthi = 0;
-               rda.seqno = 0;
-               if (z < priv->rxbufcnt - 1)
-                       rda.link = addr + sizeof(rda_t);
-               else
-                       rda.link = 1;
-               rda.inuse = 1;
-               memcpy_toio(priv->base + addr, &rda, sizeof(rda_t));
-
-               baddr += PKTSIZE;
-               raddr += sizeof(rra_t);
-               addr += sizeof(rda_t);
-       }
-
-       /* initialize current pointers */
-
-       priv->nextrxdescr = 0;
-       priv->lastrxdescr = priv->rxbufcnt - 1;
-       priv->nexttxdescr = 0;
-       priv->currtxdescr = 0;
-       priv->txusedcnt = 0;
-       memset(priv->txused, 0, sizeof(priv->txused));
-}
-
-/* set up Rx + Tx descriptors in SONIC */
-
-static int InitSONIC(struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-
-       /* set up start & end of resource area */
-
-       outw(0, SONIC_URRA);
-       outw(priv->rrastart, dev->base_addr + SONIC_RSA);
-       outw(priv->rrastart + (priv->rxbufcnt * sizeof(rra_t)), dev->base_addr + SONIC_REA);
-       outw(priv->rrastart, dev->base_addr + SONIC_RRP);
-       outw(priv->rrastart, dev->base_addr + SONIC_RWP);
-
-       /* set EOBC so that only one packet goes into one buffer */
-
-       outw((PKTSIZE - 4) >> 1, dev->base_addr + SONIC_EOBC);
-
-       /* let SONIC read the first RRA descriptor */
-
-       outw(CMDREG_RRRA, dev->base_addr + SONIC_CMDREG);
-       if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_RRRA, 0, 2)) {
-               printk(KERN_ERR "%s: SONIC did not respond on RRRA command - giving up.", dev->name);
-               return 0;
-       }
-
-       /* point SONIC to the first RDA */
-
-       outw(0, dev->base_addr + SONIC_URDA);
-       outw(priv->rdastart, dev->base_addr + SONIC_CRDA);
-
-       /* set upper half of TDA address */
-
-       outw(0, dev->base_addr + SONIC_UTDA);
-
-       return 1;
-}
-
-/* stop SONIC so we can reinitialize it */
-
-static void StopSONIC(struct net_device *dev)
-{
-       /* disable interrupts */
-
-       outb(inb(dev->base_addr + BCMREG) & (~BCMREG_IEN), dev->base_addr + BCMREG);
-       outb(0, dev->base_addr + SONIC_IMREG);
-
-       /* reset the SONIC */
-
-       outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-       udelay(10);
-       outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-}
-
-/* initialize card and SONIC for proper operation */
-
-static void putcam(camentry_t * cams, int *camcnt, char *addr)
-{
-       camentry_t *pcam = cams + (*camcnt);
-       u8 *uaddr = (u8 *) addr;
-
-       pcam->index = *camcnt;
-       pcam->addr0 = (((u16) uaddr[1]) << 8) | uaddr[0];
-       pcam->addr1 = (((u16) uaddr[3]) << 8) | uaddr[2];
-       pcam->addr2 = (((u16) uaddr[5]) << 8) | uaddr[4];
-       (*camcnt)++;
-}
-
-static void InitBoard(struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       int camcnt;
-       camentry_t cams[16];
-       u32 cammask;
-       struct netdev_hw_addr *ha;
-       u16 rcrval;
-
-       /* reset the SONIC */
-
-       outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-       udelay(10);
-
-       /* clear all spurious interrupts */
-
-       outw(inw(dev->base_addr + SONIC_ISREG), dev->base_addr + SONIC_ISREG);
-
-       /* set up the SONIC's bus interface - constant for this adapter -
-          must be done while the SONIC is in reset */
-
-       outw(DCREG_USR1 | DCREG_USR0 | DCREG_WC1 | DCREG_DW32, dev->base_addr + SONIC_DCREG);
-       outw(0, dev->base_addr + SONIC_DCREG2);
-
-       /* remove reset form the SONIC */
-
-       outw(0, dev->base_addr + SONIC_CMDREG);
-       udelay(10);
-
-       /* data sheet requires URRA to be programmed before setting up the CAM contents */
-
-       outw(0, dev->base_addr + SONIC_URRA);
-
-       /* program the CAM entry 0 to the device address */
-
-       camcnt = 0;
-       putcam(cams, &camcnt, dev->dev_addr);
-
-       /* start putting the multicast addresses into the CAM list.  Stop if
-          it is full. */
-
-       netdev_for_each_mc_addr(ha, dev) {
-               putcam(cams, &camcnt, ha->addr);
-               if (camcnt == 16)
-                       break;
-       }
-
-       /* calculate CAM mask */
-
-       cammask = (1 << camcnt) - 1;
-
-       /* feed CDA into SONIC, initialize RCR value (always get broadcasts) */
-
-       memcpy_toio(priv->base, cams, sizeof(camentry_t) * camcnt);
-       memcpy_toio(priv->base + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
-
-#ifdef DEBUG
-       printk("CAM setup:\n");
-       dumpmem(dev, 0, sizeof(camentry_t) * camcnt + sizeof(cammask));
-#endif
-
-       outw(0, dev->base_addr + SONIC_CAMPTR);
-       outw(camcnt, dev->base_addr + SONIC_CAMCNT);
-       outw(CMDREG_LCAM, dev->base_addr + SONIC_CMDREG);
-       if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_LCAM, 0, 2)) {
-               printk(KERN_ERR "%s:SONIC did not respond on LCAM command - giving up.", dev->name);
-               return;
-       } else {
-               /* clear interrupt condition */
-
-               outw(ISREG_LCD, dev->base_addr + SONIC_ISREG);
-
-#ifdef DEBUG
-               printk("Loading CAM done, address pointers %04x:%04x\n",
-                      inw(dev->base_addr + SONIC_URRA),
-                      inw(dev->base_addr + SONIC_CAMPTR));
-               {
-                       int z;
-
-                       printk("\n-->CAM: PTR %04x CNT %04x\n",
-                              inw(dev->base_addr + SONIC_CAMPTR),
-                              inw(dev->base_addr + SONIC_CAMCNT));
-                       outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-                       for (z = 0; z < camcnt; z++) {
-                               outw(z, dev->base_addr + SONIC_CAMEPTR);
-                               printk("Entry %d: %04x %04x %04x\n", z,
-                                      inw(dev->base_addr + SONIC_CAMADDR0),
-                                      inw(dev->base_addr + SONIC_CAMADDR1),
-                                      inw(dev->base_addr + SONIC_CAMADDR2));
-                       }
-                       outw(0, dev->base_addr + SONIC_CMDREG);
-               }
-#endif
-       }
-
-       rcrval = RCREG_BRD | RCREG_LB_NONE;
-
-       /* if still multicast addresses left or ALLMULTI is set, set the multicast
-          enable bit */
-
-       if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > camcnt)
-               rcrval |= RCREG_AMC;
-
-       /* promiscuous mode ? */
-
-       if (dev->flags & IFF_PROMISC)
-               rcrval |= RCREG_PRO;
-
-       /* program receive mode */
-
-       outw(rcrval, dev->base_addr + SONIC_RCREG);
-#ifdef DEBUG
-       printk("\nRCRVAL: %04x\n", rcrval);
-#endif
-
-       /* set up descriptors in shared memory + feed them into SONIC registers */
-
-       InitDscrs(dev);
-       if (!InitSONIC(dev))
-               return;
-
-       /* reset all pending interrupts */
-
-       outw(0xffff, dev->base_addr + SONIC_ISREG);
-
-       /* enable transmitter + receiver interrupts */
-
-       outw(CMDREG_RXEN, dev->base_addr + SONIC_CMDREG);
-       outw(IMREG_PRXEN | IMREG_RBEEN | IMREG_PTXEN | IMREG_TXEREN, dev->base_addr + SONIC_IMREG);
-
-       /* turn on card interrupts */
-
-       outb(inb(dev->base_addr + BCMREG) | BCMREG_IEN, dev->base_addr + BCMREG);
-
-#ifdef DEBUG
-       printk("Register dump after initialization:\n");
-       dumpregs(dev);
-#endif
-}
-
-/* start transmission of a descriptor */
-
-static void StartTx(struct net_device *dev, int descr)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       int addr;
-
-       addr = priv->tdastart + (descr * sizeof(tda_t));
-
-       /* put descriptor address into SONIC */
-
-       outw(addr, dev->base_addr + SONIC_CTDA);
-
-       /* trigger transmitter */
-
-       priv->currtxdescr = descr;
-       outw(CMDREG_TXP, dev->base_addr + SONIC_CMDREG);
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* receive buffer area exhausted */
-
-static void irqrbe_handler(struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-
-       /* point the SONIC back to the RRA start */
-
-       outw(priv->rrastart, dev->base_addr + SONIC_RRP);
-       outw(priv->rrastart, dev->base_addr + SONIC_RWP);
-}
-
-/* receive interrupt */
-
-static void irqrx_handler(struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       rda_t rda;
-       u32 rdaaddr, lrdaaddr;
-
-       /* loop until ... */
-
-       while (1) {
-               /* read descriptor that was next to be filled by SONIC */
-
-               rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t));
-               lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t));
-               memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t));
-
-               /* iron out upper word halves of fields we use - SONIC will duplicate
-                  bits 0..15 to 16..31 */
-
-               rda.status &= 0xffff;
-               rda.length &= 0xffff;
-               rda.startlo &= 0xffff;
-
-               /* stop if the SONIC still owns it, i.e. there is no data for us */
-
-               if (rda.inuse)
-                       break;
-
-               /* good packet? */
-
-               else if (rda.status & RCREG_PRX) {
-                       struct sk_buff *skb;
-
-                       /* fetch buffer */
-
-                       skb = netdev_alloc_skb(dev, rda.length + 2);
-                       if (skb == NULL)
-                               dev->stats.rx_dropped++;
-                       else {
-                               /* copy out data */
-
-                               memcpy_fromio(skb_put(skb, rda.length),
-                                              priv->base +
-                                              rda.startlo, rda.length);
-
-                               /* set up skb fields */
-
-                               skb->protocol = eth_type_trans(skb, dev);
-                               skb_checksum_none_assert(skb);
-
-                               /* bookkeeping */
-                               dev->stats.rx_packets++;
-                               dev->stats.rx_bytes += rda.length;
-
-                               /* pass to the upper layers */
-                               netif_rx(skb);
-                       }
-               }
-
-               /* otherwise check error status bits and increase statistics */
-
-               else {
-                       dev->stats.rx_errors++;
-                       if (rda.status & RCREG_FAER)
-                               dev->stats.rx_frame_errors++;
-                       if (rda.status & RCREG_CRCR)
-                               dev->stats.rx_crc_errors++;
-               }
-
-               /* descriptor processed, will become new last descriptor in queue */
-
-               rda.link = 1;
-               rda.inuse = 1;
-               memcpy_toio(priv->base + rdaaddr, &rda,
-                            sizeof(rda_t));
-
-               /* set up link and EOL = 0 in currently last descriptor. Only write
-                  the link field since the SONIC may currently already access the
-                  other fields. */
-
-               memcpy_toio(priv->base + lrdaaddr + 20, &rdaaddr, 4);
-
-               /* advance indices */
-
-               priv->lastrxdescr = priv->nextrxdescr;
-               if ((++priv->nextrxdescr) >= priv->rxbufcnt)
-                       priv->nextrxdescr = 0;
-       }
-}
-
-/* transmit interrupt */
-
-static void irqtx_handler(struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       tda_t tda;
-
-       /* fetch descriptor (we forgot the size ;-) */
-       memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
-
-       /* update statistics */
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += tda.length;
-
-       /* update our pointers */
-       priv->txused[priv->currtxdescr] = 0;
-       priv->txusedcnt--;
-
-       /* if there are more descriptors present in RAM, start them */
-       if (priv->txusedcnt > 0)
-               StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
-
-       /* tell the upper layer we can go on transmitting */
-       netif_wake_queue(dev);
-}
-
-static void irqtxerr_handler(struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       tda_t tda;
-
-       /* fetch descriptor to check status */
-       memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
-
-       /* update statistics */
-       dev->stats.tx_errors++;
-       if (tda.status & (TCREG_NCRS | TCREG_CRSL))
-               dev->stats.tx_carrier_errors++;
-       if (tda.status & TCREG_EXC)
-               dev->stats.tx_aborted_errors++;
-       if (tda.status & TCREG_OWC)
-               dev->stats.tx_window_errors++;
-       if (tda.status & TCREG_FU)
-               dev->stats.tx_fifo_errors++;
-
-       /* update our pointers */
-       priv->txused[priv->currtxdescr] = 0;
-       priv->txusedcnt--;
-
-       /* if there are more descriptors present in RAM, start them */
-       if (priv->txusedcnt > 0)
-               StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
-
-       /* tell the upper layer we can go on transmitting */
-       netif_wake_queue(dev);
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int dummy, void *device)
-{
-       struct net_device *dev = device;
-       u16 ival;
-
-       /* in case we're not meant... */
-       if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND))
-               return IRQ_NONE;
-
-       /* loop through the interrupt bits until everything is clear */
-       while (1) {
-               ival = inw(dev->base_addr + SONIC_ISREG);
-
-               if (ival & ISREG_RBE) {
-                       irqrbe_handler(dev);
-                       outw(ISREG_RBE, dev->base_addr + SONIC_ISREG);
-               }
-               if (ival & ISREG_PKTRX) {
-                       irqrx_handler(dev);
-                       outw(ISREG_PKTRX, dev->base_addr + SONIC_ISREG);
-               }
-               if (ival & ISREG_TXDN) {
-                       irqtx_handler(dev);
-                       outw(ISREG_TXDN, dev->base_addr + SONIC_ISREG);
-               }
-               if (ival & ISREG_TXER) {
-                       irqtxerr_handler(dev);
-                       outw(ISREG_TXER, dev->base_addr + SONIC_ISREG);
-               }
-               break;
-       }
-       return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-#if 0 /* info available elsewhere, but this is kept for reference */
-static int ibmlana_getinfo(char *buf, int slot, void *d)
-{
-       int len = 0, i;
-       struct net_device *dev = (struct net_device *) d;
-       ibmlana_priv *priv;
-
-       /* can't say anything about an uninitialized device... */
-
-       if (dev == NULL)
-               return len;
-       priv = netdev_priv(dev);
-
-       /* print info */
-
-       len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
-       len += sprintf(buf + len, "I/O: %#lx\n", dev->base_addr);
-       len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, dev->mem_end - 1);
-       len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
-       len += sprintf(buf + len, "Device: %s\n", dev->name);
-       len += sprintf(buf + len, "MAC address:");
-       for (i = 0; i < 6; i++)
-               len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
-       buf[len++] = '\n';
-       buf[len] = 0;
-
-       return len;
-}
-#endif
-
-/* open driver.  Means also initialization and start of LANCE */
-
-static int ibmlana_open(struct net_device *dev)
-{
-       int result;
-       ibmlana_priv *priv = netdev_priv(dev);
-
-       /* register resources - only necessary for IRQ */
-
-       result = request_irq(priv->realirq, irq_handler, IRQF_SHARED,
-                            dev->name, dev);
-       if (result != 0) {
-               printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq);
-               return result;
-       }
-       dev->irq = priv->realirq;
-
-       /* set up the card and SONIC */
-       InitBoard(dev);
-
-       /* initialize operational flags */
-       netif_start_queue(dev);
-       return 0;
-}
-
-/* close driver.  Shut down board and free allocated resources */
-
-static int ibmlana_close(struct net_device *dev)
-{
-       /* turn off board */
-
-       /* release resources */
-       if (dev->irq != 0)
-               free_irq(dev->irq, dev);
-       dev->irq = 0;
-       return 0;
-}
-
-/* transmit a block. */
-
-static netdev_tx_t ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
-{
-       ibmlana_priv *priv = netdev_priv(dev);
-       int tmplen, addr;
-       unsigned long flags;
-       tda_t tda;
-       int baddr;
-
-       /* find out if there are free slots for a frame to transmit. If not,
-          the upper layer is in deep desperation and we simply ignore the frame. */
-
-       if (priv->txusedcnt >= TXBUFCNT) {
-               dev->stats.tx_dropped++;
-               goto tx_done;
-       }
-
-       /* copy the frame data into the next free transmit buffer - fillup missing */
-       tmplen = skb->len;
-       if (tmplen < 60)
-               tmplen = 60;
-       baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);
-       memcpy_toio(priv->base + baddr, skb->data, skb->len);
-
-       /* copy filler into RAM - in case we're filling up...
-          we're filling a bit more than necessary, but that doesn't harm
-          since the buffer is far larger...
-          Sorry Linus for the filler string but I couldn't resist ;-) */
-
-       if (tmplen > skb->len) {
-               char *fill = "NetBSD is a nice OS too! ";
-               unsigned int destoffs = skb->len, l = strlen(fill);
-
-               while (destoffs < tmplen) {
-                       memcpy_toio(priv->base + baddr + destoffs, fill, l);
-                       destoffs += l;
-               }
-       }
-
-       /* set up the new frame descriptor */
-       addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t));
-       memcpy_fromio(&tda, priv->base + addr, sizeof(tda_t));
-       tda.length = tda.fraglength = tmplen;
-       memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
-
-       /* if there were no active descriptors, trigger the SONIC */
-       spin_lock_irqsave(&priv->lock, flags);
-
-       priv->txusedcnt++;
-       priv->txused[priv->nexttxdescr] = 1;
-
-       /* are all transmission slots used up ? */
-       if (priv->txusedcnt >= TXBUFCNT)
-               netif_stop_queue(dev);
-
-       if (priv->txusedcnt == 1)
-               StartTx(dev, priv->nexttxdescr);
-       priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT;
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-tx_done:
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-/* switch receiver mode. */
-
-static void ibmlana_set_multicast_list(struct net_device *dev)
-{
-       /* first stop the SONIC... */
-       StopSONIC(dev);
-       /* ...then reinit it with the new flags */
-       InitBoard(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int ibmlana_irq;
-static int ibmlana_io;
-static int startslot;          /* counts through slots when probing multiple devices */
-
-static short ibmlana_adapter_ids[] __initdata = {
-       IBM_LANA_ID,
-       0x0000
-};
-
-static char *ibmlana_adapter_names[] = {
-       "IBM LAN Adapter/A",
-       NULL
-};
-
-
-static const struct net_device_ops ibmlana_netdev_ops = {
-       .ndo_open               = ibmlana_open,
-       .ndo_stop               = ibmlana_close,
-       .ndo_start_xmit         = ibmlana_tx,
-       .ndo_set_rx_mode        = ibmlana_set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int ibmlana_init_one(struct device *kdev)
-{
-       struct mca_device *mdev = to_mca_device(kdev);
-       struct net_device *dev;
-       int slot = mdev->slot, z, rc;
-       int base = 0, irq = 0, iobase = 0, memlen = 0;
-       ibmlana_priv *priv;
-       ibmlana_medium medium;
-
-       dev = alloc_etherdev(sizeof(ibmlana_priv));
-       if (!dev)
-               return -ENOMEM;
-
-       dev->irq = ibmlana_irq;
-       dev->base_addr = ibmlana_io;
-
-       base = dev->mem_start;
-       irq = dev->irq;
-
-       /* deduce card addresses */
-       getaddrs(mdev, &base, &memlen, &iobase, &irq, &medium);
-
-       /* were we looking for something different ? */
-       if (dev->irq && dev->irq != irq) {
-               rc = -ENODEV;
-               goto err_out;
-       }
-       if (dev->mem_start && dev->mem_start != base) {
-               rc = -ENODEV;
-               goto err_out;
-       }
-
-       /* announce success */
-       printk(KERN_INFO "%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1);
-
-       /* try to obtain I/O range */
-       if (!request_region(iobase, IBM_LANA_IORANGE, DRV_NAME)) {
-               printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase);
-               startslot = slot + 1;
-               rc = -EBUSY;
-               goto err_out;
-       }
-
-       priv = netdev_priv(dev);
-       priv->slot = slot;
-       priv->realirq = mca_device_transform_irq(mdev, irq);
-       priv->medium = medium;
-       spin_lock_init(&priv->lock);
-
-       /* set base + irq for this device (irq not allocated so far) */
-
-       dev->irq = 0;
-       dev->mem_start = base;
-       dev->mem_end = base + memlen;
-       dev->base_addr = iobase;
-
-       priv->base = ioremap(base, memlen);
-       if (!priv->base) {
-               printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME);
-               startslot = slot + 1;
-               rc = -EBUSY;
-               goto err_out_reg;
-       }
-
-       mca_device_set_name(mdev, ibmlana_adapter_names[mdev->index]);
-       mca_device_set_claim(mdev, 1);
-
-       /* set methods */
-       dev->netdev_ops = &ibmlana_netdev_ops;
-       dev->flags |= IFF_MULTICAST;
-
-       /* copy out MAC address */
-
-       for (z = 0; z < ETH_ALEN; z++)
-               dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z);
-
-       /* print config */
-
-       printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
-              "MAC address %pM.\n",
-              dev->name, priv->realirq, dev->base_addr,
-              dev->mem_start, dev->mem_end - 1,
-              dev->dev_addr);
-       printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
-       /* reset board */
-
-       ResetBoard(dev);
-
-       /* next probe will start at next slot */
-
-       startslot = slot + 1;
-
-       rc = register_netdev(dev);
-       if (rc)
-               goto err_out_claimed;
-
-       dev_set_drvdata(kdev, dev);
-       return 0;
-
-err_out_claimed:
-       mca_device_set_claim(mdev, 0);
-       iounmap(priv->base);
-err_out_reg:
-       release_region(iobase, IBM_LANA_IORANGE);
-err_out:
-       free_netdev(dev);
-       return rc;
-}
-
-static int ibmlana_remove_one(struct device *kdev)
-{
-       struct mca_device *mdev = to_mca_device(kdev);
-       struct net_device *dev = dev_get_drvdata(kdev);
-       ibmlana_priv *priv = netdev_priv(dev);
-
-       unregister_netdev(dev);
-       /*DeinitBoard(dev); */
-       release_region(dev->base_addr, IBM_LANA_IORANGE);
-       mca_device_set_claim(mdev, 0);
-       iounmap(priv->base);
-       free_netdev(dev);
-       return 0;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-module_param_named(irq, ibmlana_irq, int, 0);
-module_param_named(io, ibmlana_io, int, 0);
-MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
-MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
-MODULE_LICENSE("GPL");
-
-static struct mca_driver ibmlana_driver = {
-       .id_table = ibmlana_adapter_ids,
-       .driver = {
-               .name   = "ibmlana",
-               .bus    = &mca_bus_type,
-               .probe  = ibmlana_init_one,
-               .remove = ibmlana_remove_one,
-       },
-};
-
-static int __init ibmlana_init_module(void)
-{
-       return mca_register_driver(&ibmlana_driver);
-}
-
-static void __exit ibmlana_cleanup_module(void)
-{
-       mca_unregister_driver(&ibmlana_driver);
-}
-
-module_init(ibmlana_init_module);
-module_exit(ibmlana_cleanup_module);
diff --git a/drivers/net/ethernet/natsemi/ibmlana.h b/drivers/net/ethernet/natsemi/ibmlana.h
deleted file mode 100644 (file)
index accd5ef..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-#ifndef _IBM_LANA_INCLUDE_
-#define _IBM_LANA_INCLUDE_
-
-#ifdef _IBM_LANA_DRIVER_
-
-/* maximum packet size */
-
-#define PKTSIZE 1524
-
-/* number of transmit buffers */
-
-#define TXBUFCNT 4
-
-/* Adapter ID's */
-#define IBM_LANA_ID 0xffe0
-
-/* media enumeration - defined in a way that it fits onto the LAN/A's
-   POS registers... */
-
-typedef enum {
-       Media_10BaseT, Media_10Base5,
-       Media_Unknown, Media_10Base2, Media_Count
-} ibmlana_medium;
-
-/* private structure */
-
-typedef struct {
-       unsigned int slot;              /* MCA-Slot-#                       */
-       int realirq;                    /* memorizes actual IRQ, even when
-                                          currently not allocated          */
-       ibmlana_medium medium;          /* physical cannector               */
-       u32     tdastart, txbufstart,   /* addresses                        */
-               rrastart, rxbufstart, rdastart, rxbufcnt, txusedcnt;
-       int     nextrxdescr,            /* next rx descriptor to be used    */
-               lastrxdescr,            /* last free rx descriptor          */
-               nexttxdescr,            /* last tx descriptor to be used    */
-               currtxdescr,            /* tx descriptor currently tx'ed    */
-               txused[TXBUFCNT];       /* busy flags                       */
-       void __iomem *base;
-       spinlock_t lock;
-} ibmlana_priv;
-
-/* this card uses quite a lot of I/O ports...luckily the MCA bus decodes
-   a full 64K I/O range... */
-
-#define IBM_LANA_IORANGE 0xa0
-
-/* Command Register: */
-
-#define SONIC_CMDREG     0x00
-#define CMDREG_HTX       0x0001        /* halt transmission                */
-#define CMDREG_TXP       0x0002        /* start transmission               */
-#define CMDREG_RXDIS     0x0004        /* disable receiver                 */
-#define CMDREG_RXEN      0x0008        /* enable receiver                  */
-#define CMDREG_STP       0x0010        /* stop timer                       */
-#define CMDREG_ST        0x0020        /* start timer                      */
-#define CMDREG_RST       0x0080        /* software reset                   */
-#define CMDREG_RRRA      0x0100        /* force SONIC to read first RRA    */
-#define CMDREG_LCAM      0x0200        /* force SONIC to read CAM descrs   */
-
-/* Data Configuration Register */
-
-#define SONIC_DCREG      0x02
-#define DCREG_EXBUS      0x8000        /* Extended Bus Mode                */
-#define DCREG_LBR        0x2000        /* Latched Bus Retry                */
-#define DCREG_PO1        0x1000        /* Programmable Outputs             */
-#define DCREG_PO0        0x0800
-#define DCREG_SBUS       0x0400        /* Synchronous Bus Mode             */
-#define DCREG_USR1       0x0200        /* User Definable Pins              */
-#define DCREG_USR0       0x0100
-#define DCREG_WC0        0x0000        /* 0..3 Wait States                 */
-#define DCREG_WC1        0x0040
-#define DCREG_WC2        0x0080
-#define DCREG_WC3        0x00c0
-#define DCREG_DW16       0x0000        /* 16 bit Bus Mode                  */
-#define DCREG_DW32       0x0020        /* 32 bit Bus Mode                  */
-#define DCREG_BMS        0x0010        /* Block Mode Select                */
-#define DCREG_RFT4       0x0000        /* 4/8/16/24 bytes RX  Threshold    */
-#define DCREG_RFT8       0x0004
-#define DCREG_RFT16      0x0008
-#define DCREG_RFT24      0x000c
-#define DCREG_TFT8       0x0000        /* 8/16/24/28 bytes TX Threshold    */
-#define DCREG_TFT16      0x0001
-#define DCREG_TFT24      0x0002
-#define DCREG_TFT28      0x0003
-
-/* Receive Control Register */
-
-#define SONIC_RCREG      0x04
-#define RCREG_ERR        0x8000        /* accept damaged and collided pkts */
-#define RCREG_RNT        0x4000        /* accept packets that are < 64     */
-#define RCREG_BRD        0x2000        /* accept broadcasts                */
-#define RCREG_PRO        0x1000        /* promiscuous mode                  */
-#define RCREG_AMC        0x0800        /* accept all multicasts            */
-#define RCREG_LB_NONE    0x0000        /* no loopback                      */
-#define RCREG_LB_MAC     0x0200        /* MAC loopback                     */
-#define RCREG_LB_ENDEC   0x0400        /* ENDEC loopback                   */
-#define RCREG_LB_XVR     0x0600        /* Transceiver loopback             */
-#define RCREG_MC         0x0100        /* Multicast received               */
-#define RCREG_BC         0x0080        /* Broadcast received               */
-#define RCREG_LPKT       0x0040        /* last packet in RBA               */
-#define RCREG_CRS        0x0020        /* carrier sense present            */
-#define RCREG_COL        0x0010        /* recv'd packet with collision     */
-#define RCREG_CRCR       0x0008        /* recv'd packet with CRC error     */
-#define RCREG_FAER       0x0004        /* recv'd packet with inv. framing  */
-#define RCREG_LBK        0x0002        /* recv'd loopback packet           */
-#define RCREG_PRX        0x0001        /* recv'd packet is OK              */
-
-/* Transmit Control Register */
-
-#define SONIC_TCREG      0x06
-#define TCREG_PINT       0x8000        /* generate interrupt after TDA read */
-#define TCREG_POWC       0x4000        /* timer start out of window detect */
-#define TCREG_CRCI       0x2000        /* inhibit CRC generation           */
-#define TCREG_EXDIS      0x1000        /* disable excessive deferral timer */
-#define TCREG_EXD        0x0400        /* excessive deferral occurred       */
-#define TCREG_DEF        0x0200        /* single deferral occurred          */
-#define TCREG_NCRS       0x0100        /* no carrier detected              */
-#define TCREG_CRSL       0x0080        /* carrier lost                     */
-#define TCREG_EXC        0x0040        /* excessive collisions occurred     */
-#define TCREG_OWC        0x0020        /* out of window collision occurred  */
-#define TCREG_PMB        0x0008        /* packet monitored bad             */
-#define TCREG_FU         0x0004        /* FIFO underrun                    */
-#define TCREG_BCM        0x0002        /* byte count mismatch of fragments */
-#define TCREG_PTX        0x0001        /* packet transmitted OK            */
-
-/* Interrupt Mask Register */
-
-#define SONIC_IMREG      0x08
-#define IMREG_BREN       0x4000        /* interrupt when bus retry occurred */
-#define IMREG_HBLEN      0x2000        /* interrupt when heartbeat lost    */
-#define IMREG_LCDEN      0x1000        /* interrupt when CAM loaded        */
-#define IMREG_PINTEN     0x0800        /* interrupt when PINT in TDA set   */
-#define IMREG_PRXEN      0x0400        /* interrupt when packet received   */
-#define IMREG_PTXEN      0x0200        /* interrupt when packet was sent   */
-#define IMREG_TXEREN     0x0100        /* interrupt when send failed       */
-#define IMREG_TCEN       0x0080        /* interrupt when timer completed   */
-#define IMREG_RDEEN      0x0040        /* interrupt when RDA exhausted     */
-#define IMREG_RBEEN      0x0020        /* interrupt when RBA exhausted     */
-#define IMREG_RBAEEN     0x0010        /* interrupt when RBA too short     */
-#define IMREG_CRCEN      0x0008        /* interrupt when CRC counter rolls */
-#define IMREG_FAEEN      0x0004        /* interrupt when FAE counter rolls */
-#define IMREG_MPEN       0x0002        /* interrupt when MP counter rolls  */
-#define IMREG_RFOEN      0x0001        /* interrupt when Rx FIFO overflows */
-
-/* Interrupt Status Register */
-
-#define SONIC_ISREG      0x0a
-#define ISREG_BR         0x4000        /* bus retry occurred                */
-#define ISREG_HBL        0x2000        /* heartbeat lost                   */
-#define ISREG_LCD        0x1000        /* CAM loaded                       */
-#define ISREG_PINT       0x0800        /* PINT in TDA set                  */
-#define ISREG_PKTRX      0x0400        /* packet received                  */
-#define ISREG_TXDN       0x0200        /* packet was sent                  */
-#define ISREG_TXER       0x0100        /* send failed                      */
-#define ISREG_TC         0x0080        /* timer completed                  */
-#define ISREG_RDE        0x0040        /* RDA exhausted                    */
-#define ISREG_RBE        0x0020        /* RBA exhausted                    */
-#define ISREG_RBAE       0x0010        /* RBA too short for received frame */
-#define ISREG_CRC        0x0008        /* CRC counter rolls over           */
-#define ISREG_FAE        0x0004        /* FAE counter rolls over           */
-#define ISREG_MP         0x0002        /* MP counter rolls  over           */
-#define ISREG_RFO        0x0001        /* Rx FIFO overflows                */
-
-#define SONIC_UTDA       0x0c  /* current transmit descr address   */
-#define SONIC_CTDA       0x0e
-
-#define SONIC_URDA       0x1a  /* current receive descr address    */
-#define SONIC_CRDA       0x1c
-
-#define SONIC_CRBA0      0x1e  /* current receive buffer address   */
-#define SONIC_CRBA1      0x20
-
-#define SONIC_RBWC0      0x22  /* word count in receive buffer     */
-#define SONIC_RBWC1      0x24
-
-#define SONIC_EOBC       0x26  /* minimum space to be free in RBA  */
-
-#define SONIC_URRA       0x28  /* upper address of CDA & Recv Area */
-
-#define SONIC_RSA        0x2a  /* start of receive resource area   */
-
-#define SONIC_REA        0x2c  /* end of receive resource area     */
-
-#define SONIC_RRP        0x2e  /* resource read pointer            */
-
-#define SONIC_RWP        0x30  /* resource write pointer           */
-
-#define SONIC_CAMEPTR    0x42  /* CAM entry pointer                */
-
-#define SONIC_CAMADDR2   0x44  /* CAM address ports                */
-#define SONIC_CAMADDR1   0x46
-#define SONIC_CAMADDR0   0x48
-
-#define SONIC_CAMPTR     0x4c  /* lower address of CDA             */
-
-#define SONIC_CAMCNT     0x4e  /* # of CAM descriptors to load     */
-
-/* Data Configuration Register 2    */
-
-#define SONIC_DCREG2     0x7e
-#define DCREG2_EXPO3     0x8000        /* extended programmable outputs    */
-#define DCREG2_EXPO2     0x4000
-#define DCREG2_EXPO1     0x2000
-#define DCREG2_EXPO0     0x1000
-#define DCREG2_HD        0x0800        /* heartbeat disable                */
-#define DCREG2_JD        0x0200        /* jabber timer disable             */
-#define DCREG2_AUTO      0x0100        /* enable AUI/TP auto selection     */
-#define DCREG2_XWRAP     0x0040        /* TP transceiver loopback          */
-#define DCREG2_PH        0x0010        /* HOLD request timing              */
-#define DCREG2_PCM       0x0004        /* packet compress when matched     */
-#define DCREG2_PCNM      0x0002        /* packet compress when not matched */
-#define DCREG2_RJCM      0x0001        /* inverse packet match via CAM     */
-
-/* Board Control Register: Enable RAM, Interrupts... */
-
-#define BCMREG           0x80
-#define BCMREG_RAMEN     0x80  /* switch over to RAM               */
-#define BCMREG_IPEND     0x40  /* interrupt pending ?              */
-#define BCMREG_RESET     0x08  /* reset board                      */
-#define BCMREG_16BIT     0x04  /* adapter in 16-bit slot           */
-#define BCMREG_RAMWIN    0x02  /* enable RAM window                */
-#define BCMREG_IEN       0x01  /* interrupt enable                 */
-
-/* MAC Address PROM */
-
-#define MACADDRPROM      0x92
-
-/* structure of a CAM entry */
-
-typedef struct {
-       u32 index;              /* pointer into CAM area            */
-       u32 addr0;              /* address part (bits 0..15 used)   */
-       u32 addr1;
-       u32 addr2;
-} camentry_t;
-
-/* structure of a receive resource */
-
-typedef struct {
-       u32 startlo;            /* start address (bits 0..15 used)  */
-       u32 starthi;
-       u32 cntlo;              /* size in 16-bit quantities        */
-       u32 cnthi;
-} rra_t;
-
-/* structure of a receive descriptor */
-
-typedef struct {
-       u32 status;             /* packet status                    */
-       u32 length;             /* length in bytes                  */
-       u32 startlo;            /* start address                    */
-       u32 starthi;
-       u32 seqno;              /* frame sequence                   */
-       u32 link;               /* pointer to next descriptor       */
-       /* bit 0 = EOL                      */
-       u32 inuse;              /* !=0 --> free for SONIC to write  */
-} rda_t;
-
-/* structure of a transmit descriptor */
-
-typedef struct {
-       u32 status;             /* transmit status                  */
-       u32 config;             /* value for TCR                    */
-       u32 length;             /* total length                     */
-       u32 fragcount;          /* number of fragments              */
-       u32 startlo;            /* start address of fragment        */
-       u32 starthi;
-       u32 fraglength;         /* length of this fragment          */
-       /* more address/length triplets may */
-       /* follow here                      */
-       u32 link;               /* pointer to next descriptor       */
-       /* bit 0 = EOL                      */
-} tda_t;
-
-#endif                         /* _IBM_LANA_DRIVER_ */
-
-#endif /* _IBM_LANA_INCLUDE_ */
index f4ad60c97eae4b0f271923694b19dd187416445c..7a5e295588b0740f38c288364de1a51be6898fd9 100644 (file)
@@ -862,9 +862,6 @@ static int natsemi_probe1(struct pci_dev *pdev, const struct pci_device_id *ent)
                prev_eedata = eedata;
        }
 
-       /* Store MAC Address in perm_addr */
-       memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
-
        np = netdev_priv(dev);
        np->ioaddr = ioaddr;
 
index 7c94c089212f9ffe638b0628ffb1635be407c19c..bfd887382e1962cfc5d73ef71813ad5a04084688 100644 (file)
@@ -8014,7 +8014,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        /*  Set the factory defined MAC address initially   */
        dev->addr_len = ETH_ALEN;
        memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
-       memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
 
        /* initialize number of multicast & unicast MAC entries variables */
        if (sp->device_type == XFRAME_I_DEVICE) {
index 92dd72d3f9de39a70bb141848614753e7c23b4ba..f8f073880f84bccd5f0daedb8c1f08233c43e6c8 100644 (file)
@@ -82,9 +82,9 @@ static void vxge_ethtool_gdrvinfo(struct net_device *dev,
                                  struct ethtool_drvinfo *info)
 {
        struct vxgedev *vdev = netdev_priv(dev);
-       strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(VXGE_DRIVER_NAME));
-       strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
-       strlcpy(info->fw_version, vdev->fw_version, VXGE_HW_FW_STRLEN);
+       strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, vdev->fw_version, sizeof(info->fw_version));
        strlcpy(info->bus_info, pci_name(vdev->pdev), sizeof(info->bus_info));
        info->regdump_len = sizeof(struct vxge_hw_vpath_reg)
                                * vdev->no_of_vpath;
index 7c87105ca04999d55d4fea2f5f2adc9d3846a660..794444e09492978ffd5154e065a0a2bd5fbe846f 100644 (file)
@@ -4682,7 +4682,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
        /* Store the fw version for ethttool option */
        strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version);
        memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN);
-       memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN);
 
        /* Copy the station mac address to the list */
        for (i = 0; i < vdev->no_of_vpath; i++) {
index cbd6a529d0c0d94d130dfb16f8703db6c1139fb4..162da8975b059a3ef42ec9e2469660e02d3b01de 100644 (file)
@@ -878,8 +878,8 @@ static int w90p910_ether_ioctl(struct net_device *dev,
 static void w90p910_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int w90p910_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 87fa5919c455224f8ee6ab47a4bae742e7fc801f..0b8de12bcbca998410f2097d27e239eb31607f83 100644 (file)
@@ -3055,7 +3055,6 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
 
        /* synchronized against open : rtnl_lock() held by caller */
        memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
        if (netif_running(dev)) {
                netif_tx_lock_bh(dev);
@@ -5766,9 +5765,8 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
                        "%s: set workaround bit for reversed mac addr\n",
                        __func__);
        }
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
-       if (!is_valid_ether_addr(dev->perm_addr)) {
+       if (!is_valid_ether_addr(dev->dev_addr)) {
                /*
                 * Bad mac address. At least one bios sets the mac address
                 * to 01:23:45:67:89:ab
index 3466ca1e8f6c0c11edc26a06b86b83595ed014a0..c4122c86f829293cc60d6dd48c72602d7dded49f 100644 (file)
@@ -800,7 +800,7 @@ static int lpc_mii_probe(struct net_device *ndev)
        else
                netdev_info(ndev, "using RMII interface\n");
        phydev = phy_connect(ndev, dev_name(&phydev->dev),
-                            &lpc_handle_link_change, 0,
+                            &lpc_handle_link_change,
                             lpc_phy_interface_mode(&pldat->pdev->dev));
 
        if (IS_ERR(phydev)) {
@@ -1239,9 +1239,10 @@ static int lpc_eth_open(struct net_device *ndev)
 static void lpc_eth_ethtool_getdrvinfo(struct net_device *ndev,
        struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, MODNAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, dev_name(ndev->dev.parent));
+       strlcpy(info->driver, MODNAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, dev_name(ndev->dev.parent),
+               sizeof(info->bus_info));
 }
 
 static u32 lpc_eth_ethtool_getmsglevel(struct net_device *ndev)
index b5499198e0290dd329e44486c5d54a1db3a1f893..921729f9c85c53baa17cd334f4a7b8f35f590561 100644 (file)
@@ -1350,10 +1350,10 @@ static void octeon_mgmt_poll_controller(struct net_device *netdev)
 static void octeon_mgmt_get_drvinfo(struct net_device *netdev,
                                    struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, DRV_NAME, sizeof(info->driver));
-       strncpy(info->version, DRV_VERSION, sizeof(info->version));
-       strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
-       strncpy(info->bus_info, "N/A", sizeof(info->bus_info));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
        info->n_stats = 0;
        info->testinfo_len = 0;
        info->regdump_len = 0;
@@ -1534,12 +1534,10 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
 
        mac = of_get_mac_address(pdev->dev.of_node);
 
-       if (mac && is_valid_ether_addr(mac)) {
+       if (mac && is_valid_ether_addr(mac))
                memcpy(netdev->dev_addr, mac, ETH_ALEN);
-               netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
-       } else {
+       else
                eth_hw_addr_random(netdev);
-       }
 
        p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
 
index bf829ee30077ac0b4716f6ca04101669aea549af..cac33e5f9bc2635cd2a4fd9b38c1af6f155164d8 100644 (file)
@@ -1808,9 +1808,10 @@ static int check_if_running(struct net_device *dev)
 static void hamachi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct hamachi_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int hamachi_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index fbaed4fa72fa01798ec058b2381c9af381839eab..d28593b1fc3e8664b1f6aad8e6d53dba4fdd1a5c 100644 (file)
@@ -1326,9 +1326,10 @@ static void set_rx_mode(struct net_device *dev)
 static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct yellowfin_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops ethtool_ops = {
index 69e321a650779c9d3bae975a273035b922fca08f..7a849fc55a6674a3879699ca73ef99756d824fa8 100644 (file)
@@ -501,12 +501,11 @@ netxen_read_mac_addr(struct netxen_adapter *adapter)
        for (i = 0; i < 6; i++)
                netdev->dev_addr[i] = *(p + 5 - i);
 
-       memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
        memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
 
        /* set station address */
 
-       if (!is_valid_ether_addr(netdev->perm_addr))
+       if (!is_valid_ether_addr(netdev->dev_addr))
                dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr);
 
        return 0;
index 67a679aaf29adf949a2b8dfa79e230b308807615..c0ed12d325b462865a6a6914a1e0b6f197b576cd 100644 (file)
@@ -3867,7 +3867,6 @@ static int ql3xxx_probe(struct pci_dev *pdev,
                ndev->mtu = qdev->nvram_data.macCfg_port0.etherMtu_mac ;
                ql_set_mac_addr(ndev, qdev->nvram_data.funcCfg_fn0.macAddress);
        }
-       memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
 
        ndev->tx_queue_len = NUM_REQ_Q_ENTRIES;
 
index c4b8ced8382989ac539ea9458f74082f0e735866..7722a203e388f6d7a0e75fc60248467e920cc4e5 100644 (file)
@@ -6,4 +6,6 @@ obj-$(CONFIG_QLCNIC) := qlcnic.o
 
 qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
        qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
-       qlcnic_sysfs.o qlcnic_minidump.o
+       qlcnic_sysfs.o qlcnic_minidump.o qlcnic_83xx_hw.o \
+       qlcnic_83xx_init.o qlcnic_83xx_vnic.o \
+       qlcnic_minidump.o
index bc7ec64e9c7a965c53fe7435e598e4310687c8ea..f71aef58f84d9ec8e03d6acb35a55f2f2abc9268 100644 (file)
 #include <linux/if_vlan.h>
 
 #include "qlcnic_hdr.h"
+#include "qlcnic_hw.h"
+#include "qlcnic_83xx_hw.h"
 
 #define _QLCNIC_LINUX_MAJOR 5
-#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 30
-#define QLCNIC_LINUX_VERSIONID  "5.0.30"
+#define _QLCNIC_LINUX_MINOR 1
+#define _QLCNIC_LINUX_SUBVERSION 32
+#define QLCNIC_LINUX_VERSIONID  "5.1.32"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -96,7 +98,6 @@
 #define TX_STOP_THRESH         ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
                                                        + MGMT_CMD_DESC_RESV)
 #define QLCNIC_MAX_TX_TIMEOUTS 2
-
 /*
  * Following are the states of the Phantom. Phantom will set them and
  * Host will read to check if the fields are correct.
@@ -203,6 +204,7 @@ struct uni_data_desc{
 
 /* Flash Defines and Structures */
 #define QLCNIC_FLT_LOCATION    0x3F1000
+#define QLCNIC_FDT_LOCATION     0x3F0000
 #define QLCNIC_B0_FW_IMAGE_REGION 0x74
 #define QLCNIC_C0_FW_IMAGE_REGION 0x97
 #define QLCNIC_BOOTLD_REGION    0X72
@@ -223,6 +225,36 @@ struct qlcnic_flt_entry {
        u32 end_addr;
 };
 
+/* Flash Descriptor Table */
+struct qlcnic_fdt {
+       u32     valid;
+       u16     ver;
+       u16     len;
+       u16     cksum;
+       u16     unused;
+       u8      model[16];
+       u16     mfg_id;
+       u16     id;
+       u8      flag;
+       u8      erase_cmd;
+       u8      alt_erase_cmd;
+       u8      write_enable_cmd;
+       u8      write_enable_bits;
+       u8      write_statusreg_cmd;
+       u8      unprotected_sec_cmd;
+       u8      read_manuf_cmd;
+       u32     block_size;
+       u32     alt_block_size;
+       u32     flash_size;
+       u32     write_enable_data;
+       u8      readid_addr_len;
+       u8      write_disable_bits;
+       u8      read_dev_id_len;
+       u8      chip_erase_cmd;
+       u16     read_timeo;
+       u8      protected_sec_cmd;
+       u8      resvd[65];
+};
 /* Magic number to let user know flash is programmed */
 #define        QLCNIC_BDINFO_MAGIC 0x12345678
 
@@ -267,6 +299,12 @@ struct qlcnic_flt_entry {
 
 extern char qlcnic_driver_name[];
 
+extern int qlcnic_use_msi;
+extern int qlcnic_use_msi_x;
+extern int qlcnic_auto_fw_reset;
+extern int qlcnic_load_fw_file;
+extern int qlcnic_config_npars;
+
 /* Number of status descriptors to handle per interrupt */
 #define MAX_STATUS_HANDLE      (64)
 
@@ -314,6 +352,7 @@ struct qlcnic_rx_buffer {
 
 #define QLCNIC_INTR_DEFAULT                    0x04
 #define QLCNIC_CONFIG_INTR_COALESCE            3
+#define QLCNIC_DEV_INFO_SIZE                   1
 
 struct qlcnic_nic_intr_coalesce {
        u8      type;
@@ -337,6 +376,7 @@ struct qlcnic_dump_template_hdr {
        u32     sys_info[3];
        u32     saved_state[16];
        u32     cap_sizes[8];
+       u32     ocm_wnd_reg[16];
        u32     rsvd[0];
 };
 
@@ -396,12 +436,24 @@ struct qlcnic_hardware_context {
        u16 act_pci_func;
 
        u32 capabilities;
+       u32 capabilities2;
        u32 temp;
        u32 int_vec_bit;
        u32 fw_hal_version;
+       u32 port_config;
        struct qlcnic_hardware_ops *hw_ops;
        struct qlcnic_nic_intr_coalesce coal;
        struct qlcnic_fw_dump fw_dump;
+       struct qlcnic_fdt fdt;
+       struct qlc_83xx_reset reset;
+       struct qlc_83xx_idc idc;
+       struct qlc_83xx_fw_info fw_info;
+       struct qlcnic_intrpt_config *intr_tbl;
+       u32 *reg_tbl;
+       u32 *ext_reg_tbl;
+       u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
+       u32 mbox_reg[4];
+       spinlock_t mbx_lock;
 };
 
 struct qlcnic_adapter_stats {
@@ -422,6 +474,8 @@ struct qlcnic_adapter_stats {
        u64  null_rxbuf;
        u64  rx_dma_map_error;
        u64  tx_dma_map_error;
+       u64  spurious_intr;
+       u64  mac_filter_limit_overrun;
 };
 
 /*
@@ -460,12 +514,17 @@ struct qlcnic_host_sds_ring {
 } ____cacheline_internodealigned_in_smp;
 
 struct qlcnic_host_tx_ring {
+       int irq;
+       void __iomem *crb_intr_mask;
+       char name[IFNAMSIZ+4];
        u16 ctx_id;
        u32 producer;
        u32 sw_consumer;
        u32 num_desc;
        void __iomem *crb_cmd_producer;
        struct cmd_desc_type0 *desc_head;
+       struct qlcnic_adapter *adapter;
+       struct napi_struct napi;
        struct qlcnic_cmd_buffer *cmd_buf_arr;
        __le32 *hw_consumer;
 
@@ -492,8 +551,6 @@ struct qlcnic_recv_context {
 /* HW context creation */
 
 #define QLCNIC_OS_CRB_RETRY_COUNT      4000
-#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \
-       (((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16))
 
 #define QLCNIC_CDRP_CMD_BIT            0x80000000
 
@@ -513,43 +570,6 @@ struct qlcnic_recv_context {
  * the crb QLCNIC_CDRP_CRB_OFFSET.
  */
 #define QLCNIC_CDRP_FORM_CMD(cmd)      (QLCNIC_CDRP_CMD_BIT | (cmd))
-#define QLCNIC_CDRP_IS_CMD(cmd)        (((cmd) & QLCNIC_CDRP_CMD_BIT) != 0)
-
-#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES     0x00000001
-#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX    0x00000002
-#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX    0x00000003
-#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX  0x00000004
-#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX         0x00000005
-#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX         0x00000006
-#define QLCNIC_CDRP_CMD_CREATE_RX_CTX           0x00000007
-#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX          0x00000008
-#define QLCNIC_CDRP_CMD_CREATE_TX_CTX           0x00000009
-#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX          0x0000000a
-#define QLCNIC_CDRP_CMD_INTRPT_TEST            0x00000011
-#define QLCNIC_CDRP_CMD_SET_MTU                 0x00000012
-#define QLCNIC_CDRP_CMD_READ_PHY               0x00000013
-#define QLCNIC_CDRP_CMD_WRITE_PHY              0x00000014
-#define QLCNIC_CDRP_CMD_READ_HW_REG            0x00000015
-#define QLCNIC_CDRP_CMD_GET_FLOW_CTL           0x00000016
-#define QLCNIC_CDRP_CMD_SET_FLOW_CTL           0x00000017
-#define QLCNIC_CDRP_CMD_READ_MAX_MTU           0x00000018
-#define QLCNIC_CDRP_CMD_READ_MAX_LRO           0x00000019
-#define QLCNIC_CDRP_CMD_MAC_ADDRESS            0x0000001f
-
-#define QLCNIC_CDRP_CMD_GET_PCI_INFO           0x00000020
-#define QLCNIC_CDRP_CMD_GET_NIC_INFO           0x00000021
-#define QLCNIC_CDRP_CMD_SET_NIC_INFO           0x00000022
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024
-#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH         0x00000025
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS     0x00000026
-#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING      0x00000027
-#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH      0x00000028
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG        0x00000029
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS      0x0000002a
-#define QLCNIC_CDRP_CMD_CONFIG_PORT            0x0000002E
-#define QLCNIC_CDRP_CMD_TEMP_SIZE              0x0000002f
-#define QLCNIC_CDRP_CMD_GET_TEMP_HDR           0x00000030
-#define QLCNIC_CDRP_CMD_GET_MAC_STATS          0x00000037
 
 #define QLCNIC_RCODE_SUCCESS           0
 #define QLCNIC_RCODE_INVALID_ARGS      6
@@ -726,6 +746,11 @@ struct qlcnic_mac_list_s {
        uint8_t mac_addr[ETH_ALEN+2];
 };
 
+/* MAC Learn */
+#define NO_MAC_LEARN           0
+#define DRV_MAC_LEARN          1
+#define FDB_MAC_LEARN          2
+
 #define QLCNIC_HOST_REQUEST    0x13
 #define QLCNIC_REQUEST         0x14
 
@@ -762,7 +787,7 @@ struct qlcnic_mac_list_s {
  */
 
 #define QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK              0x8f
-#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE       141
+#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE       0x8D
 
 #define VPORT_MISS_MODE_DROP           0 /* drop all unmatched */
 #define VPORT_MISS_MODE_ACCEPT_ALL     1 /* accept all packets */
@@ -779,6 +804,8 @@ struct qlcnic_mac_list_s {
 #define QLCNIC_FW_CAPABILITY_MORE_CAPS         BIT_31
 
 #define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2
+#define QLCNIC_FW_CAP2_HW_LRO_IPV6             BIT_3
+#define QLCNIC_FW_CAPABILITY_2_OCBB            BIT_5
 
 /* module types */
 #define LINKEVENT_MODULE_NOT_PRESENT                   1
@@ -855,7 +882,7 @@ struct qlcnic_ipaddr {
 
 #define QLCNIC_MSI_ENABLED             0x02
 #define QLCNIC_MSIX_ENABLED            0x04
-#define QLCNIC_LRO_ENABLED             0x08
+#define QLCNIC_LRO_ENABLED             0x01
 #define QLCNIC_LRO_DISABLED            0x00
 #define QLCNIC_BRIDGE_ENABLED          0X10
 #define QLCNIC_DIAG_ENABLED            0x20
@@ -887,6 +914,7 @@ struct qlcnic_ipaddr {
 #define __QLCNIC_AER                   5
 #define __QLCNIC_DIAG_RES_ALLOC                6
 #define __QLCNIC_LED_ENABLE            7
+#define __QLCNIC_ELB_INPROGRESS        8
 
 #define QLCNIC_INTERRUPT_TEST          1
 #define QLCNIC_LOOPBACK_TEST           2
@@ -895,12 +923,14 @@ struct qlcnic_ipaddr {
 #define QLCNIC_FILTER_AGE      80
 #define QLCNIC_READD_AGE       20
 #define QLCNIC_LB_MAX_FILTERS  64
+#define QLCNIC_LB_BUCKET_SIZE  32
 
 /* QLCNIC Driver Error Code */
 #define QLCNIC_FW_NOT_RESPOND          51
 #define QLCNIC_TEST_IN_PROGRESS                52
 #define QLCNIC_UNDEFINED_ERROR         53
 #define QLCNIC_LB_CABLE_NOT_CONN       54
+#define QLCNIC_ILB_MAX_RCV_LOOP        10
 
 struct qlcnic_filter {
        struct hlist_node fnode;
@@ -912,7 +942,8 @@ struct qlcnic_filter {
 struct qlcnic_filter_hash {
        struct hlist_head *fhead;
        u8 fnum;
-       u8 fmax;
+       u16 fmax;
+       u16 fbucket_size;
 };
 
 struct qlcnic_adapter {
@@ -934,6 +965,7 @@ struct qlcnic_adapter {
 
        u8 max_rds_rings;
        u8 max_sds_rings;
+       u8 rx_csum;
        u8 portnum;
 
        u8 fw_wait_cnt;
@@ -954,8 +986,10 @@ struct qlcnic_adapter {
        u8 mac_addr[ETH_ALEN];
 
        u64 dev_rst_time;
-       u8 mac_learn;
+       bool drv_mac_learn;
+       bool fdb_mac_learn;
        unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];
+       u8 flash_mfg_id;
        struct qlcnic_npar_info *npars;
        struct qlcnic_eswitch *eswitch;
        struct qlcnic_nic_template *nic_ops;
@@ -969,7 +1003,9 @@ struct qlcnic_adapter {
        void __iomem    *isr_int_vec;
 
        struct msix_entry *msix_entries;
+       struct workqueue_struct *qlcnic_wq;
        struct delayed_work fw_work;
+       struct delayed_work idc_aen_work;
 
        struct qlcnic_filter_hash fhash;
 
@@ -995,7 +1031,24 @@ struct qlcnic_info_le {
        __le16  max_rx_ques;
        __le16  min_tx_bw;
        __le16  max_tx_bw;
-       u8      reserved2[104];
+       __le32  op_type;
+       __le16  max_bw_reg_offset;
+       __le16  max_linkspeed_reg_offset;
+       __le32  capability1;
+       __le32  capability2;
+       __le32  capability3;
+       __le16  max_tx_mac_filters;
+       __le16  max_rx_mcast_mac_filters;
+       __le16  max_rx_ucast_mac_filters;
+       __le16  max_rx_ip_addr;
+       __le16  max_rx_lro_flow;
+       __le16  max_rx_status_rings;
+       __le16  max_rx_buf_rings;
+       __le16  max_tx_vlan_keys;
+       u8      total_pf;
+       u8      total_rss_engines;
+       __le16  max_vports;
+       u8      reserved2[64];
 } __packed;
 
 struct qlcnic_info {
@@ -1005,12 +1058,28 @@ struct qlcnic_info {
        u16     switch_mode;
        u32     capabilities;
        u8      max_mac_filters;
-       u8      reserved1;
        u16     max_mtu;
        u16     max_tx_ques;
        u16     max_rx_ques;
        u16     min_tx_bw;
        u16     max_tx_bw;
+       u32     op_type;
+       u16     max_bw_reg_offset;
+       u16     max_linkspeed_reg_offset;
+       u32     capability1;
+       u32     capability2;
+       u32     capability3;
+       u16     max_tx_mac_filters;
+       u16     max_rx_mcast_mac_filters;
+       u16     max_rx_ucast_mac_filters;
+       u16     max_rx_ip_addr;
+       u16     max_rx_lro_flow;
+       u16     max_rx_status_rings;
+       u16     max_rx_buf_rings;
+       u16     max_tx_vlan_keys;
+       u8      total_pf;
+       u8      total_rss_engines;
+       u16     max_vports;
 };
 
 struct qlcnic_pci_info_le {
@@ -1024,7 +1093,9 @@ struct qlcnic_pci_info_le {
        __le16  reserved1[2];
 
        u8      mac[ETH_ALEN];
-       u8      reserved2[106];
+       __le16  func_count;
+       u8      reserved2[104];
+
 } __packed;
 
 struct qlcnic_pci_info {
@@ -1035,6 +1106,7 @@ struct qlcnic_pci_info {
        u16     tx_min_bw;
        u16     tx_max_bw;
        u8      mac[ETH_ALEN];
+       u16  func_count;
 };
 
 struct qlcnic_npar_info {
@@ -1266,10 +1338,8 @@ struct qlcnic_esw_statistics {
 #define QLCNIC_RESET_QUIESCENT         0xadd00020
 
 struct _cdrp_cmd {
-       u32 cmd;
-       u32 arg1;
-       u32 arg2;
-       u32 arg3;
+       u32 num;
+       u32 *arg;
 };
 
 struct qlcnic_cmd_args {
@@ -1279,9 +1349,6 @@ struct qlcnic_cmd_args {
 
 int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
 int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
-
-int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
-int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data);
 int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);
 int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data);
 void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *, u64, u64 *);
@@ -1291,9 +1358,10 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);
        (((addr) < (high)) && ((addr) >= (low)))
 
 #define QLCRD32(adapter, off) \
-       (qlcnic_hw_read_wx_2M(adapter, off))
+       (adapter->ahw->hw_ops->read_reg)(adapter, off)
+
 #define QLCWR32(adapter, off, val) \
-       (qlcnic_hw_write_wx_2M(adapter, off, val))
+       adapter->ahw->hw_ops->write_reg(adapter, off, val)
 
 int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32);
 void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
@@ -1306,10 +1374,6 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
        qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID)
 #define qlcnic_phy_unlock(a)   \
        qlcnic_pcie_sem_unlock((a), 3)
-#define qlcnic_api_lock(a)     \
-       qlcnic_pcie_sem_lock((a), 5, 0)
-#define qlcnic_api_unlock(a)   \
-       qlcnic_pcie_sem_unlock((a), 5)
 #define qlcnic_sw_lock(a)      \
        qlcnic_pcie_sem_lock((a), 6, 0)
 #define qlcnic_sw_unlock(a)    \
@@ -1324,14 +1388,13 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
 
 #define MAX_CTL_CHECK 1000
 
-int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
 int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
-int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
 void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
 void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
 int qlcnic_dump_fw(struct qlcnic_adapter *);
 
 /* Functions from qlcnic_init.c */
+void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int);
 int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
 int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
 void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
@@ -1361,54 +1424,40 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
 int qlcnic_check_fw_status(struct qlcnic_adapter *adapter);
 void qlcnic_watchdog_task(struct work_struct *work);
 void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_rds_ring *rds_ring);
+               struct qlcnic_host_rds_ring *rds_ring, u8 ring_id);
 int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
 void qlcnic_set_multi(struct net_device *netdev);
+int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *);
+int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
 void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
-int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter);
-int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd);
-int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable);
-void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
 
 int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *);
 int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
 netdev_features_t qlcnic_fix_features(struct net_device *netdev,
        netdev_features_t features);
 int qlcnic_set_features(struct net_device *netdev, netdev_features_t features);
-int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
 int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
 int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *);
-void qlcnic_fetch_mac(u32, u32, u8, u8 *);
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter);
-int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode);
 
 /* Functions from qlcnic_ethtool.c */
 int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);
 
 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
-void qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *);
 void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val);
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
-void qlcnic_dev_request_reset(struct qlcnic_adapter *);
+int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
+int qlcnic_validate_max_rss(u8, u8);
 void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
-
-/* Management functions */
-int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
-int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
-int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
-int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
 
 /*  eSwitch management functions */
 int qlcnic_config_switch_port(struct qlcnic_adapter *,
                                struct qlcnic_esw_func_cfg *);
+
 int qlcnic_get_eswitch_port_config(struct qlcnic_adapter *,
                                struct qlcnic_esw_func_cfg *);
 int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
@@ -1418,14 +1467,12 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8,
                                        struct __qlcnic_esw_statistics *);
 int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
 int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
-extern int qlcnic_config_tso;
 
-int qlcnic_napi_add(struct qlcnic_adapter *, struct net_device *);
-void qlcnic_napi_del(struct qlcnic_adapter *adapter);
-void qlcnic_napi_enable(struct qlcnic_adapter *adapter);
-void qlcnic_napi_disable(struct qlcnic_adapter *adapter);
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd);
+
 int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *, int);
 void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
+void qlcnic_advert_link_change(struct qlcnic_adapter *, int);
 void qlcnic_free_tx_rings(struct qlcnic_adapter *);
 int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);
 
@@ -1433,6 +1480,9 @@ void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
 void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
 void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
 void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter);
+
 int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
 int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
 void qlcnic_set_vlan_config(struct qlcnic_adapter *,
@@ -1440,6 +1490,20 @@ void qlcnic_set_vlan_config(struct qlcnic_adapter *,
 void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *,
                                      struct qlcnic_esw_func_cfg *);
 
+void qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+int qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+void __qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_detach(struct qlcnic_adapter *);
+void qlcnic_teardown_intr(struct qlcnic_adapter *);
+int qlcnic_attach(struct qlcnic_adapter *);
+int __qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_restore_indev_addr(struct net_device *, unsigned long);
+
+int qlcnic_check_temp(struct qlcnic_adapter *);
+int qlcnic_init_pci_info(struct qlcnic_adapter *);
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_reset_npar_config(struct qlcnic_adapter *);
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
 /*
  * QLOGIC Board information
  */
@@ -1462,6 +1526,277 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
                                tx_ring->producer;
 }
 
+struct qlcnic_nic_template {
+       int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
+       int (*config_led) (struct qlcnic_adapter *, u32, u32);
+       int (*start_firmware) (struct qlcnic_adapter *);
+       int (*init_driver) (struct qlcnic_adapter *);
+       void (*request_reset) (struct qlcnic_adapter *, u32);
+       void (*cancel_idc_work) (struct qlcnic_adapter *);
+       int (*napi_add)(struct qlcnic_adapter *, struct net_device *);
+       void (*napi_del)(struct qlcnic_adapter *);
+       void (*config_ipaddr)(struct qlcnic_adapter *, __be32, int);
+       irqreturn_t (*clear_legacy_intr)(struct qlcnic_adapter *);
+};
+
+/* Adapter hardware abstraction */
+struct qlcnic_hardware_ops {
+       void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+       void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+       int (*read_reg) (struct qlcnic_adapter *, ulong);
+       int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
+       void (*get_ocm_win) (struct qlcnic_hardware_context *);
+       int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
+       int (*setup_intr) (struct qlcnic_adapter *, u8);
+       int (*alloc_mbx_args)(struct qlcnic_cmd_args *,
+                             struct qlcnic_adapter *, u32);
+       int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+       void (*get_func_no) (struct qlcnic_adapter *);
+       int (*api_lock) (struct qlcnic_adapter *);
+       void (*api_unlock) (struct qlcnic_adapter *);
+       void (*add_sysfs) (struct qlcnic_adapter *);
+       void (*remove_sysfs) (struct qlcnic_adapter *);
+       void (*process_lb_rcv_ring_diag) (struct qlcnic_host_sds_ring *);
+       int (*create_rx_ctx) (struct qlcnic_adapter *);
+       int (*create_tx_ctx) (struct qlcnic_adapter *,
+       struct qlcnic_host_tx_ring *, int);
+       int (*setup_link_event) (struct qlcnic_adapter *, int);
+       int (*get_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *, u8);
+       int (*get_pci_info) (struct qlcnic_adapter *, struct qlcnic_pci_info *);
+       int (*set_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *);
+       int (*change_macvlan) (struct qlcnic_adapter *, u8*, __le16, u8);
+       void (*napi_enable) (struct qlcnic_adapter *);
+       void (*napi_disable) (struct qlcnic_adapter *);
+       void (*config_intr_coal) (struct qlcnic_adapter *);
+       int (*config_rss) (struct qlcnic_adapter *, int);
+       int (*config_hw_lro) (struct qlcnic_adapter *, int);
+       int (*config_loopback) (struct qlcnic_adapter *, u8);
+       int (*clear_loopback) (struct qlcnic_adapter *, u8);
+       int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
+       void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, __le16);
+       int (*get_board_info) (struct qlcnic_adapter *);
+};
+
+extern struct qlcnic_nic_template qlcnic_vf_ops;
+
+static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+{
+       return adapter->nic_ops->start_firmware(adapter);
+}
+
+static inline void qlcnic_read_crb(struct qlcnic_adapter *adapter, char *buf,
+                                  loff_t offset, size_t size)
+{
+       adapter->ahw->hw_ops->read_crb(adapter, buf, offset, size);
+}
+
+static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf,
+                                   loff_t offset, size_t size)
+{
+       adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size);
+}
+
+static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter,
+                                      ulong off)
+{
+       return adapter->ahw->hw_ops->read_reg(adapter, off);
+}
+
+static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter,
+                                       ulong off, u32 data)
+{
+       return adapter->ahw->hw_ops->write_reg(adapter, off, data);
+}
+
+static inline int qlcnic_get_mac_address(struct qlcnic_adapter *adapter,
+                                        u8 *mac)
+{
+       return adapter->ahw->hw_ops->get_mac_address(adapter, mac);
+}
+
+static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+{
+       return adapter->ahw->hw_ops->setup_intr(adapter, num_intr);
+}
+
+static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+                                       struct qlcnic_adapter *adapter, u32 arg)
+{
+       return adapter->ahw->hw_ops->alloc_mbx_args(mbx, adapter, arg);
+}
+
+static inline int qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
+                                  struct qlcnic_cmd_args *cmd)
+{
+       return adapter->ahw->hw_ops->mbx_cmd(adapter, cmd);
+}
+
+static inline void qlcnic_get_func_no(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->get_func_no(adapter);
+}
+
+static inline int qlcnic_api_lock(struct qlcnic_adapter *adapter)
+{
+       return adapter->ahw->hw_ops->api_lock(adapter);
+}
+
+static inline void qlcnic_api_unlock(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->api_unlock(adapter);
+}
+
+static inline void qlcnic_add_sysfs(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->add_sysfs(adapter);
+}
+
+static inline void qlcnic_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->remove_sysfs(adapter);
+}
+
+static inline void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+       sds_ring->adapter->ahw->hw_ops->process_lb_rcv_ring_diag(sds_ring);
+}
+
+static inline int qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+       return adapter->ahw->hw_ops->create_rx_ctx(adapter);
+}
+
+static inline int qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
+                                             struct qlcnic_host_tx_ring *ptr,
+                                             int ring)
+{
+       return adapter->ahw->hw_ops->create_tx_ctx(adapter, ptr, ring);
+}
+
+static inline int qlcnic_linkevent_request(struct qlcnic_adapter *adapter,
+                                          int enable)
+{
+       return adapter->ahw->hw_ops->setup_link_event(adapter, enable);
+}
+
+static inline int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+                                     struct qlcnic_info *info, u8 id)
+{
+       return adapter->ahw->hw_ops->get_nic_info(adapter, info, id);
+}
+
+static inline int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+                                     struct qlcnic_pci_info *info)
+{
+       return adapter->ahw->hw_ops->get_pci_info(adapter, info);
+}
+
+static inline int qlcnic_set_nic_info(struct qlcnic_adapter *adapter,
+                                     struct qlcnic_info *info)
+{
+       return adapter->ahw->hw_ops->set_nic_info(adapter, info);
+}
+
+static inline int qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter,
+                                           u8 *addr, __le16 id, u8 cmd)
+{
+       return adapter->ahw->hw_ops->change_macvlan(adapter, addr, id, cmd);
+}
+
+static inline int qlcnic_napi_add(struct qlcnic_adapter *adapter,
+                                 struct net_device *netdev)
+{
+       return adapter->nic_ops->napi_add(adapter, netdev);
+}
+
+static inline void qlcnic_napi_del(struct qlcnic_adapter *adapter)
+{
+       adapter->nic_ops->napi_del(adapter);
+}
+
+static inline void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->napi_enable(adapter);
+}
+
+static inline void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->napi_disable(adapter);
+}
+
+static inline void qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->config_intr_coal(adapter);
+}
+
+static inline int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+       return adapter->ahw->hw_ops->config_rss(adapter, enable);
+}
+
+static inline int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter,
+                                      int enable)
+{
+       return adapter->ahw->hw_ops->config_hw_lro(adapter, enable);
+}
+
+static inline int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+       return adapter->ahw->hw_ops->config_loopback(adapter, mode);
+}
+
+static inline int qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+       return adapter->ahw->hw_ops->config_loopback(adapter, mode);
+}
+
+static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter,
+                                        u32 mode)
+{
+       return adapter->ahw->hw_ops->config_promisc_mode(adapter, mode);
+}
+
+static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter,
+                                       u64 *addr, __le16 id)
+{
+       adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id);
+}
+
+static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+{
+       return adapter->ahw->hw_ops->get_board_info(adapter);
+}
+
+static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
+                                           u32 key)
+{
+       adapter->nic_ops->request_reset(adapter, key);
+}
+
+static inline void qlcnic_cancel_idc_work(struct qlcnic_adapter *adapter)
+{
+       adapter->nic_ops->cancel_idc_work(adapter);
+}
+
+static inline irqreturn_t
+qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+       return adapter->nic_ops->clear_legacy_intr(adapter);
+}
+
+static inline int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state,
+                                   u32 rate)
+{
+       return adapter->nic_ops->config_led(adapter, state, rate);
+}
+
+static inline void qlcnic_config_ipaddr(struct qlcnic_adapter *adapter,
+                                       __be32 ip, int cmd)
+{
+       adapter->nic_ops->config_ipaddr(adapter, ip, cmd);
+}
+
 static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
 {
        writel(0, sds_ring->crb_intr_mask);
@@ -1480,12 +1815,6 @@ static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
 extern const struct ethtool_ops qlcnic_ethtool_ops;
 extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
 
-struct qlcnic_nic_template {
-       int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
-       int (*config_led) (struct qlcnic_adapter *, u32, u32);
-       int (*start_firmware) (struct qlcnic_adapter *);
-};
-
 #define QLCDB(adapter, lvl, _fmt, _args...) do {       \
        if (NETIF_MSG_##lvl & adapter->ahw->msg_enable) \
                printk(KERN_INFO "%s: %s: " _fmt,       \
@@ -1493,6 +1822,7 @@ struct qlcnic_nic_template {
                        __func__, ##_args);             \
        } while (0)
 
+#define PCI_DEVICE_ID_QLOGIC_QLE834X    0x8030
 #define PCI_DEVICE_ID_QLOGIC_QLE824X   0x8020
 static inline bool qlcnic_82xx_check(struct qlcnic_adapter *adapter)
 {
@@ -1500,4 +1830,11 @@ static inline bool qlcnic_82xx_check(struct qlcnic_adapter *adapter)
        return (device == PCI_DEVICE_ID_QLOGIC_QLE824X) ? true : false;
 }
 
+static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter)
+{
+       unsigned short device = adapter->pdev->device;
+       return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false;
+}
+
+
 #endif                         /* __QLCNIC_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
new file mode 100644 (file)
index 0000000..46162f8
--- /dev/null
@@ -0,0 +1,2757 @@
+#include "qlcnic.h"
+#include <linux/if_vlan.h>
+#include <linux/ipv6.h>
+#include <linux/ethtool.h>
+#include <linux/interrupt.h>
+
+#define QLCNIC_MAX_TX_QUEUES           1
+
+#define QLCNIC_MBX_RSP(reg)            LSW(reg)
+#define QLCNIC_MBX_NUM_REGS(reg)       (MSW(reg) & 0x1FF)
+#define QLCNIC_MBX_STATUS(reg)         (((reg) >> 25) & 0x7F)
+#define QLCNIC_MBX_HOST(ahw, i)        ((ahw)->pci_base0 + ((i) * 4))
+#define QLCNIC_MBX_FW(ahw, i)          ((ahw)->pci_base0 + 0x800 + ((i) * 4))
+
+#define RSS_HASHTYPE_IP_TCP            0x3
+
+/* status descriptor mailbox data
+ * @phy_addr: physical address of buffer
+ * @sds_ring_size: buffer size
+ * @intrpt_id: interrupt id
+ * @intrpt_val: source of interrupt
+ */
+struct qlcnic_sds_mbx {
+       u64     phy_addr;
+       u8      rsvd1[16];
+       u16     sds_ring_size;
+       u16     rsvd2[3];
+       u16     intrpt_id;
+       u8      intrpt_val;
+       u8      rsvd3[5];
+} __packed;
+
+/* receive descriptor buffer data
+ * phy_addr_reg: physical address of regular buffer
+ * phy_addr_jmb: physical address of jumbo buffer
+ * reg_ring_sz: size of regular buffer
+ * reg_ring_len: no. of entries in regular buffer
+ * jmb_ring_len: no. of entries in jumbo buffer
+ * jmb_ring_sz: size of jumbo buffer
+ */
+struct qlcnic_rds_mbx {
+       u64     phy_addr_reg;
+       u64     phy_addr_jmb;
+       u16     reg_ring_sz;
+       u16     reg_ring_len;
+       u16     jmb_ring_sz;
+       u16     jmb_ring_len;
+} __packed;
+
+/* host producers for regular and jumbo rings */
+struct __host_producer_mbx {
+       u32     reg_buf;
+       u32     jmb_buf;
+} __packed;
+
+/* Receive context mailbox data outbox registers
+ * @state: state of the context
+ * @vport_id: virtual port id
+ * @context_id: receive context id
+ * @num_pci_func: number of pci functions of the port
+ * @phy_port: physical port id
+ */
+struct qlcnic_rcv_mbx_out {
+       u8      rcv_num;
+       u8      sts_num;
+       u16     ctx_id;
+       u8      state;
+       u8      num_pci_func;
+       u8      phy_port;
+       u8      vport_id;
+       u32     host_csmr[QLCNIC_MAX_RING_SETS];
+       struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+struct qlcnic_add_rings_mbx_out {
+       u8      rcv_num;
+       u8      sts_num;
+       u16  ctx_id;
+       u32  host_csmr[QLCNIC_MAX_RING_SETS];
+       struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+/* Transmit context mailbox inbox registers
+ * @phys_addr: DMA address of the transmit buffer
+ * @cnsmr_index: host consumer index
+ * @size: legth of transmit buffer ring
+ * @intr_id: interrput id
+ * @src: src of interrupt
+ */
+struct qlcnic_tx_mbx {
+       u64     phys_addr;
+       u64     cnsmr_index;
+       u16     size;
+       u16     intr_id;
+       u8      src;
+       u8      rsvd[3];
+} __packed;
+
+/* Transmit context mailbox outbox registers
+ * @host_prod: host producer index
+ * @ctx_id: transmit context id
+ * @state: state of the transmit context
+ */
+struct qlcnic_tx_mbx_out {
+       u32     host_prod;
+       u16     ctx_id;
+       u8      state;
+       u8      rsvd;
+} __packed;
+
+static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
+       {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
+       {QLCNIC_CMD_CONFIG_INTRPT, 18, 34},
+       {QLCNIC_CMD_CREATE_RX_CTX, 136, 27},
+       {QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},
+       {QLCNIC_CMD_CREATE_TX_CTX, 54, 18},
+       {QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},
+       {QLCNIC_CMD_CONFIGURE_MAC_LEARNING, 2, 1},
+       {QLCNIC_CMD_INTRPT_TEST, 22, 12},
+       {QLCNIC_CMD_SET_MTU, 3, 1},
+       {QLCNIC_CMD_READ_PHY, 4, 2},
+       {QLCNIC_CMD_WRITE_PHY, 5, 1},
+       {QLCNIC_CMD_READ_HW_REG, 4, 1},
+       {QLCNIC_CMD_GET_FLOW_CTL, 4, 2},
+       {QLCNIC_CMD_SET_FLOW_CTL, 4, 1},
+       {QLCNIC_CMD_READ_MAX_MTU, 4, 2},
+       {QLCNIC_CMD_READ_MAX_LRO, 4, 2},
+       {QLCNIC_CMD_MAC_ADDRESS, 4, 3},
+       {QLCNIC_CMD_GET_PCI_INFO, 1, 66},
+       {QLCNIC_CMD_GET_NIC_INFO, 2, 19},
+       {QLCNIC_CMD_SET_NIC_INFO, 32, 1},
+       {QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},
+       {QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},
+       {QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},
+       {QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},
+       {QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},
+       {QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},
+       {QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},
+       {QLCNIC_CMD_CONFIG_PORT, 4, 1},
+       {QLCNIC_CMD_TEMP_SIZE, 1, 4},
+       {QLCNIC_CMD_GET_TEMP_HDR, 5, 5},
+       {QLCNIC_CMD_GET_LINK_EVENT, 2, 1},
+       {QLCNIC_CMD_CONFIG_MAC_VLAN, 4, 3},
+       {QLCNIC_CMD_CONFIG_INTR_COAL, 6, 1},
+       {QLCNIC_CMD_CONFIGURE_RSS, 14, 1},
+       {QLCNIC_CMD_CONFIGURE_LED, 2, 1},
+       {QLCNIC_CMD_CONFIGURE_MAC_RX_MODE, 2, 1},
+       {QLCNIC_CMD_CONFIGURE_HW_LRO, 2, 1},
+       {QLCNIC_CMD_GET_STATISTICS, 2, 80},
+       {QLCNIC_CMD_SET_PORT_CONFIG, 2, 1},
+       {QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},
+       {QLCNIC_CMD_GET_LINK_STATUS, 2, 4},
+       {QLCNIC_CMD_IDC_ACK, 5, 1},
+       {QLCNIC_CMD_INIT_NIC_FUNC, 2, 1},
+       {QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
+       {QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
+       {QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
+       {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
+};
+
+static const u32 qlcnic_83xx_ext_reg_tbl[] = {
+       0x38CC,         /* Global Reset */
+       0x38F0,         /* Wildcard */
+       0x38FC,         /* Informant */
+       0x3038,         /* Host MBX ctrl */
+       0x303C,         /* FW MBX ctrl */
+       0x355C,         /* BOOT LOADER ADDRESS REG */
+       0x3560,         /* BOOT LOADER SIZE REG */
+       0x3564,         /* FW IMAGE ADDR REG */
+       0x1000,         /* MBX intr enable */
+       0x1200,         /* Default Intr mask */
+       0x1204,         /* Default Interrupt ID */
+       0x3780,         /* QLC_83XX_IDC_MAJ_VERSION */
+       0x3784,         /* QLC_83XX_IDC_DEV_STATE */
+       0x3788,         /* QLC_83XX_IDC_DRV_PRESENCE */
+       0x378C,         /* QLC_83XX_IDC_DRV_ACK */
+       0x3790,         /* QLC_83XX_IDC_CTRL */
+       0x3794,         /* QLC_83XX_IDC_DRV_AUDIT */
+       0x3798,         /* QLC_83XX_IDC_MIN_VERSION */
+       0x379C,         /* QLC_83XX_RECOVER_DRV_LOCK */
+       0x37A0,         /* QLC_83XX_IDC_PF_0 */
+       0x37A4,         /* QLC_83XX_IDC_PF_1 */
+       0x37A8,         /* QLC_83XX_IDC_PF_2 */
+       0x37AC,         /* QLC_83XX_IDC_PF_3 */
+       0x37B0,         /* QLC_83XX_IDC_PF_4 */
+       0x37B4,         /* QLC_83XX_IDC_PF_5 */
+       0x37B8,         /* QLC_83XX_IDC_PF_6 */
+       0x37BC,         /* QLC_83XX_IDC_PF_7 */
+       0x37C0,         /* QLC_83XX_IDC_PF_8 */
+       0x37C4,         /* QLC_83XX_IDC_PF_9 */
+       0x37C8,         /* QLC_83XX_IDC_PF_10 */
+       0x37CC,         /* QLC_83XX_IDC_PF_11 */
+       0x37D0,         /* QLC_83XX_IDC_PF_12 */
+       0x37D4,         /* QLC_83XX_IDC_PF_13 */
+       0x37D8,         /* QLC_83XX_IDC_PF_14 */
+       0x37DC,         /* QLC_83XX_IDC_PF_15 */
+       0x37E0,         /* QLC_83XX_IDC_DEV_PARTITION_INFO_1 */
+       0x37E4,         /* QLC_83XX_IDC_DEV_PARTITION_INFO_2 */
+       0x37F0,         /* QLC_83XX_DRV_OP_MODE */
+       0x37F4,         /* QLC_83XX_VNIC_STATE */
+       0x3868,         /* QLC_83XX_DRV_LOCK */
+       0x386C,         /* QLC_83XX_DRV_UNLOCK */
+       0x3504,         /* QLC_83XX_DRV_LOCK_ID */
+       0x34A4,         /* QLC_83XX_ASIC_TEMP */
+};
+
+static const u32 qlcnic_83xx_reg_tbl[] = {
+       0x34A8,         /* PEG_HALT_STAT1 */
+       0x34AC,         /* PEG_HALT_STAT2 */
+       0x34B0,         /* FW_HEARTBEAT */
+       0x3500,         /* FLASH LOCK_ID */
+       0x3528,         /* FW_CAPABILITIES */
+       0x3538,         /* Driver active, DRV_REG0 */
+       0x3540,         /* Device state, DRV_REG1 */
+       0x3544,         /* Driver state, DRV_REG2 */
+       0x3548,         /* Driver scratch, DRV_REG3 */
+       0x354C,         /* Device partiton info, DRV_REG4 */
+       0x3524,         /* Driver IDC ver, DRV_REG5 */
+       0x3550,         /* FW_VER_MAJOR */
+       0x3554,         /* FW_VER_MINOR */
+       0x3558,         /* FW_VER_SUB */
+       0x359C,         /* NPAR STATE */
+       0x35FC,         /* FW_IMG_VALID */
+       0x3650,         /* CMD_PEG_STATE */
+       0x373C,         /* RCV_PEG_STATE */
+       0x37B4,         /* ASIC TEMP */
+       0x356C,         /* FW API */
+       0x3570,         /* DRV OP MODE */
+       0x3850,         /* FLASH LOCK */
+       0x3854,         /* FLASH UNLOCK */
+};
+
+static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
+       .read_crb                       = qlcnic_83xx_read_crb,
+       .write_crb                      = qlcnic_83xx_write_crb,
+       .read_reg                       = qlcnic_83xx_rd_reg_indirect,
+       .write_reg                      = qlcnic_83xx_wrt_reg_indirect,
+       .get_mac_address                = qlcnic_83xx_get_mac_address,
+       .setup_intr                     = qlcnic_83xx_setup_intr,
+       .alloc_mbx_args                 = qlcnic_83xx_alloc_mbx_args,
+       .mbx_cmd                        = qlcnic_83xx_mbx_op,
+       .get_func_no                    = qlcnic_83xx_get_func_no,
+       .api_lock                       = qlcnic_83xx_cam_lock,
+       .api_unlock                     = qlcnic_83xx_cam_unlock,
+       .add_sysfs                      = qlcnic_83xx_add_sysfs,
+       .remove_sysfs                   = qlcnic_83xx_remove_sysfs,
+       .process_lb_rcv_ring_diag       = qlcnic_83xx_process_rcv_ring_diag,
+       .create_rx_ctx                  = qlcnic_83xx_create_rx_ctx,
+       .create_tx_ctx                  = qlcnic_83xx_create_tx_ctx,
+       .setup_link_event               = qlcnic_83xx_setup_link_event,
+       .get_nic_info                   = qlcnic_83xx_get_nic_info,
+       .get_pci_info                   = qlcnic_83xx_get_pci_info,
+       .set_nic_info                   = qlcnic_83xx_set_nic_info,
+       .change_macvlan                 = qlcnic_83xx_sre_macaddr_change,
+       .napi_enable                    = qlcnic_83xx_napi_enable,
+       .napi_disable                   = qlcnic_83xx_napi_disable,
+       .config_intr_coal               = qlcnic_83xx_config_intr_coal,
+       .config_rss                     = qlcnic_83xx_config_rss,
+       .config_hw_lro                  = qlcnic_83xx_config_hw_lro,
+       .config_loopback                = qlcnic_83xx_set_lb_mode,
+       .clear_loopback                 = qlcnic_83xx_clear_lb_mode,
+       .config_promisc_mode            = qlcnic_83xx_nic_set_promisc,
+       .change_l2_filter               = qlcnic_83xx_change_l2_filter,
+       .get_board_info                 = qlcnic_83xx_get_port_info,
+};
+
+static struct qlcnic_nic_template qlcnic_83xx_ops = {
+       .config_bridged_mode    = qlcnic_config_bridged_mode,
+       .config_led             = qlcnic_config_led,
+       .request_reset          = qlcnic_83xx_idc_request_reset,
+       .cancel_idc_work        = qlcnic_83xx_idc_exit,
+       .napi_add               = qlcnic_83xx_napi_add,
+       .napi_del               = qlcnic_83xx_napi_del,
+       .config_ipaddr          = qlcnic_83xx_config_ipaddr,
+       .clear_legacy_intr      = qlcnic_83xx_clear_legacy_intr,
+};
+
+void qlcnic_83xx_register_map(struct qlcnic_hardware_context *ahw)
+{
+       ahw->hw_ops             = &qlcnic_83xx_hw_ops;
+       ahw->reg_tbl            = (u32 *)qlcnic_83xx_reg_tbl;
+       ahw->ext_reg_tbl        = (u32 *)qlcnic_83xx_ext_reg_tbl;
+}
+
+int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *adapter)
+{
+       u32 fw_major, fw_minor, fw_build;
+       struct pci_dev *pdev = adapter->pdev;
+
+       fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+       fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+       fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
+       adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
+
+       dev_info(&pdev->dev, "Driver v%s, firmware version %d.%d.%d\n",
+                QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
+
+       return adapter->fw_version;
+}
+
+static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)
+{
+       void __iomem *base;
+       u32 val;
+
+       base = adapter->ahw->pci_base0 +
+              QLC_83XX_CRB_WIN_FUNC(adapter->ahw->pci_func);
+       writel(addr, base);
+       val = readl(base);
+       if (val != addr)
+               return -EIO;
+
+       return 0;
+}
+
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr)
+{
+       int ret;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       ret = __qlcnic_set_win_base(adapter, (u32) addr);
+       if (!ret) {
+               return QLCRDX(ahw, QLCNIC_WILDCARD);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "%s failed, addr = 0x%x\n", __func__, (int)addr);
+               return -EIO;
+       }
+}
+
+int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
+                                u32 data)
+{
+       int err;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       err = __qlcnic_set_win_base(adapter, (u32) addr);
+       if (!err) {
+               QLCWRX(ahw, QLCNIC_WILDCARD, data);
+               return 0;
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "%s failed, addr = 0x%x data = 0x%x\n",
+                       __func__, (int)addr, data);
+               return err;
+       }
+}
+
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+{
+       int err, i, num_msix;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (!num_intr)
+               num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+       num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
+                                             num_intr));
+       /* account for AEN interrupt MSI-X based interrupts */
+       num_msix += 1;
+       num_msix += adapter->max_drv_tx_rings;
+       err = qlcnic_enable_msix(adapter, num_msix);
+       if (err == -ENOMEM)
+               return err;
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               num_msix = adapter->ahw->num_msix;
+       else
+               num_msix = 1;
+       /* setup interrupt mapping table for fw */
+       ahw->intr_tbl = vzalloc(num_msix *
+                               sizeof(struct qlcnic_intrpt_config));
+       if (!ahw->intr_tbl)
+               return -ENOMEM;
+       if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               /* MSI-X enablement failed, use legacy interrupt */
+               adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR;
+               adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK;
+               adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR;
+               adapter->msix_entries[0].vector = adapter->pdev->irq;
+               dev_info(&adapter->pdev->dev, "using legacy interrupt\n");
+       }
+
+       for (i = 0; i < num_msix; i++) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX;
+               else
+                       ahw->intr_tbl[i].type = QLCNIC_INTRPT_INTX;
+               ahw->intr_tbl[i].id = i;
+               ahw->intr_tbl[i].src = 0;
+       }
+       return 0;
+}
+
+inline void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
+                                   struct qlcnic_host_sds_ring *sds_ring)
+{
+       writel(0, sds_ring->crb_intr_mask);
+       if (!QLCNIC_IS_MSI_FAMILY(adapter))
+               writel(0, adapter->tgt_mask_reg);
+}
+
+static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
+                                    struct qlcnic_cmd_args *cmd)
+{
+       int i;
+       for (i = 0; i < cmd->rsp.num; i++)
+               cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i));
+}
+
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+       u32 intr_val;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int retries = 0;
+
+       intr_val = readl(adapter->tgt_status_reg);
+
+       if (!QLC_83XX_VALID_INTX_BIT31(intr_val))
+               return IRQ_NONE;
+
+       if (QLC_83XX_INTX_FUNC(intr_val) != adapter->ahw->pci_func) {
+               adapter->stats.spurious_intr++;
+               return IRQ_NONE;
+       }
+       /* clear the interrupt trigger control register */
+       writel(0, adapter->isr_int_vec);
+       do {
+               intr_val = readl(adapter->tgt_status_reg);
+               if (QLC_83XX_INTX_FUNC(intr_val) != ahw->pci_func)
+                       break;
+               retries++;
+       } while (QLC_83XX_VALID_INTX_BIT30(intr_val) &&
+                (retries < QLC_83XX_LEGACY_INTX_MAX_RETRY));
+
+       if (retries == QLC_83XX_LEGACY_INTX_MAX_RETRY) {
+               dev_info(&adapter->pdev->dev,
+                        "Reached maximum retries to clear legacy interrupt\n");
+               return IRQ_NONE;
+       }
+
+       mdelay(QLC_83XX_LEGACY_INTX_DELAY);
+
+       return IRQ_HANDLED;
+}
+
+irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data)
+{
+       struct qlcnic_host_sds_ring *sds_ring = data;
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               goto done;
+
+       if (adapter->nic_ops->clear_legacy_intr(adapter) == IRQ_NONE)
+               return IRQ_NONE;
+
+done:
+       adapter->ahw->diag_cnt++;
+       qlcnic_83xx_enable_intr(adapter, sds_ring);
+
+       return IRQ_HANDLED;
+}
+
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
+{
+       u32 val = 0;
+       u32 num_msix = adapter->ahw->num_msix - 1;
+
+       val = (num_msix << 8);
+
+       QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               free_irq(adapter->msix_entries[num_msix].vector, adapter);
+}
+
+int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
+{
+       irq_handler_t handler;
+       u32 val;
+       char name[32];
+       int err = 0;
+       unsigned long flags = 0;
+
+       if (!(adapter->flags & QLCNIC_MSI_ENABLED) &&
+           !(adapter->flags & QLCNIC_MSIX_ENABLED))
+               flags |= IRQF_SHARED;
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               handler = qlcnic_83xx_handle_aen;
+               val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
+               snprintf(name, (IFNAMSIZ + 4),
+                        "%s[%s]", adapter->netdev->name, "aen");
+               err = request_irq(val, handler, flags, name, adapter);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "failed to register MBX interrupt\n");
+                       return err;
+               }
+       }
+
+       /* Enable mailbox interrupt */
+       qlcnic_83xx_enable_mbx_intrpt(adapter);
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               err = qlcnic_83xx_config_intrpt(adapter, 1);
+
+       return err;
+}
+
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *adapter)
+{
+       u32 val = QLCRDX(adapter->ahw, QLCNIC_INFORMANT);
+       adapter->ahw->pci_func = val & 0xf;
+}
+
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *adapter)
+{
+       void __iomem *addr;
+       u32 val, limit = 0;
+
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       addr = ahw->pci_base0 + QLC_83XX_SEM_LOCK_FUNC(ahw->pci_func);
+       do {
+               val = readl(addr);
+               if (val) {
+                       /* write the function number to register */
+                       QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
+                                           ahw->pci_func);
+                       return 0;
+               }
+               usleep_range(1000, 2000);
+       } while (++limit <= QLCNIC_PCIE_SEM_TIMEOUT);
+
+       return -EIO;
+}
+
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)
+{
+       void __iomem *addr;
+       u32 val;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       addr = ahw->pci_base0 + QLC_83XX_SEM_UNLOCK_FUNC(ahw->pci_func);
+       val = readl(addr);
+}
+
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
+                         loff_t offset, size_t size)
+{
+       int ret;
+       u32 data;
+
+       if (qlcnic_api_lock(adapter)) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: failed to acquire lock. addr offset 0x%x\n",
+                       __func__, (u32)offset);
+               return;
+       }
+
+       ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset);
+       qlcnic_api_unlock(adapter);
+
+       if (ret == -EIO) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: failed. addr offset 0x%x\n",
+                       __func__, (u32)offset);
+               return;
+       }
+       data = ret;
+       memcpy(buf, &data, size);
+}
+
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
+                          loff_t offset, size_t size)
+{
+       u32 data;
+
+       memcpy(&data, buf, size);
+       qlcnic_83xx_wrt_reg_indirect(adapter, (u32) offset, data);
+}
+
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
+{
+       int status;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "Get Port Info failed\n");
+       } else {
+               if (QLC_83XX_SFP_10G_CAPABLE(adapter->ahw->port_config))
+                       adapter->ahw->port_type = QLCNIC_XGBE;
+               else
+                       adapter->ahw->port_type = QLCNIC_GBE;
+
+               if (QLC_83XX_AUTONEG(adapter->ahw->port_config))
+                       adapter->ahw->link_autoneg = AUTONEG_ENABLE;
+       }
+       return status;
+}
+
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               val = BIT_2 | ((adapter->ahw->num_msix - 1) << 8);
+       else
+               val = BIT_2;
+
+       QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+}
+
+void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,
+                         const struct pci_device_id *ent)
+{
+       u32 op_mode, priv_level;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       ahw->fw_hal_version = 2;
+       qlcnic_get_func_no(adapter);
+
+       /* Determine function privilege level */
+       op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+       if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+                                                        ahw->pci_func);
+
+       if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+               dev_info(&adapter->pdev->dev,
+                        "HAL Version: %d Non Privileged function\n",
+                        ahw->fw_hal_version);
+               adapter->nic_ops = &qlcnic_vf_ops;
+       } else {
+               adapter->nic_ops = &qlcnic_83xx_ops;
+       }
+}
+
+static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
+                                       u32 data[]);
+static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
+                                           u32 data[]);
+
+static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
+                           struct qlcnic_cmd_args *cmd)
+{
+       int i;
+
+       dev_info(&adapter->pdev->dev,
+                "Host MBX regs(%d)\n", cmd->req.num);
+       for (i = 0; i < cmd->req.num; i++) {
+               if (i && !(i % 8))
+                       pr_info("\n");
+               pr_info("%08x ", cmd->req.arg[i]);
+       }
+       pr_info("\n");
+       dev_info(&adapter->pdev->dev,
+                "FW MBX regs(%d)\n", cmd->rsp.num);
+       for (i = 0; i < cmd->rsp.num; i++) {
+               if (i && !(i % 8))
+                       pr_info("\n");
+               pr_info("%08x ", cmd->rsp.arg[i]);
+       }
+       pr_info("\n");
+}
+
+static u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
+{
+       u32 data;
+       unsigned long wait_time = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       /* wait for mailbox completion */
+       do {
+               data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
+               if (++wait_time > QLCNIC_MBX_TIMEOUT) {
+                       data = QLCNIC_RCODE_TIMEOUT;
+                       break;
+               }
+               mdelay(1);
+       } while (!data);
+       return data;
+}
+
+int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
+                      struct qlcnic_cmd_args *cmd)
+{
+       int i;
+       u16 opcode;
+       u8 mbx_err_code, mac_cmd_rcode;
+       u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, temp, fw[8];
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       opcode = LSW(cmd->req.arg[0]);
+       if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+               dev_info(&adapter->pdev->dev,
+                        "Mailbox cmd attempted, 0x%x\n", opcode);
+               dev_info(&adapter->pdev->dev, "Mailbox detached\n");
+               return 0;
+       }
+
+       spin_lock(&ahw->mbx_lock);
+       mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+
+       if (mbx_val) {
+               QLCDB(adapter, DRV,
+                     "Mailbox cmd attempted, 0x%x\n", opcode);
+               QLCDB(adapter, DRV,
+                     "Mailbox not available, 0x%x, collect FW dump\n",
+                     mbx_val);
+               cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+               spin_unlock(&ahw->mbx_lock);
+               return cmd->rsp.arg[0];
+       }
+
+       /* Fill in mailbox registers */
+       mbx_cmd = cmd->req.arg[0];
+       writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
+       for (i = 1; i < cmd->req.num; i++)
+               writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
+
+       /* Signal FW about the impending command */
+       QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
+poll:
+       rsp = qlcnic_83xx_mbx_poll(adapter);
+       /* Get the FW response data */
+       fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
+       mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
+       rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
+       opcode = QLCNIC_MBX_RSP(fw_data);
+
+       if (rsp != QLCNIC_RCODE_TIMEOUT) {
+               if (opcode == QLCNIC_MBX_LINK_EVENT) {
+                       for (i = 0; i < rsp_num; i++) {
+                               temp = readl(QLCNIC_MBX_FW(ahw, i));
+                               fw[i] = temp;
+                       }
+                       qlcnic_83xx_handle_link_aen(adapter, fw);
+                       /* clear fw mbx control register */
+                       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+                       mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+                       if (mbx_val)
+                               goto poll;
+               } else if (opcode == QLCNIC_MBX_COMP_EVENT) {
+                       for (i = 0; i < rsp_num; i++) {
+                               temp = readl(QLCNIC_MBX_FW(ahw, i));
+                               fw[i] = temp;
+                       }
+                       qlcnic_83xx_handle_idc_comp_aen(adapter, fw);
+                       /* clear fw mbx control register */
+                       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+                       mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+                       if (mbx_val)
+                               goto poll;
+               } else if (opcode == QLCNIC_MBX_REQUEST_EVENT) {
+                       /* IDC Request Notification */
+                       for (i = 0; i < rsp_num; i++) {
+                               temp = readl(QLCNIC_MBX_FW(ahw, i));
+                               fw[i] = temp;
+                       }
+                       for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++) {
+                               temp = QLCNIC_MBX_RSP(fw[i]);
+                               adapter->ahw->mbox_aen[i] = temp;
+                       }
+                       queue_delayed_work(adapter->qlcnic_wq,
+                                          &adapter->idc_aen_work, 0);
+                       /* clear fw mbx control register */
+                       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+                       mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+                       if (mbx_val)
+                               goto poll;
+               } else if ((mbx_err_code == QLCNIC_MBX_RSP_OK) ||
+                          (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) {
+                       qlcnic_83xx_get_mbx_data(adapter, cmd);
+                       rsp = QLCNIC_RCODE_SUCCESS;
+               } else {
+                       qlcnic_83xx_get_mbx_data(adapter, cmd);
+                       if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
+                               fw_data = readl(QLCNIC_MBX_FW(ahw, 2));
+                               mac_cmd_rcode = (u8)fw_data;
+                               if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||
+                                   mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||
+                                   mac_cmd_rcode == QLC_83XX_MAC_ABSENT) {
+                                       rsp = QLCNIC_RCODE_SUCCESS;
+                                       goto out;
+                               }
+                       }
+                       dev_info(&adapter->pdev->dev,
+                                "MBX command 0x%x failed with err:0x%x\n",
+                                opcode, mbx_err_code);
+                       rsp = mbx_err_code;
+                       qlcnic_dump_mbx(adapter, cmd);
+               }
+       } else {
+               dev_info(&adapter->pdev->dev,
+                        "MBX command 0x%x timed out\n", opcode);
+               qlcnic_dump_mbx(adapter, cmd);
+       }
+out:
+       /* clear fw mbx control register */
+       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+       spin_unlock(&ahw->mbx_lock);
+       return rsp;
+}
+
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+                              struct qlcnic_adapter *adapter, u32 type)
+{
+       int i, size;
+       u32 temp;
+       const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+       mbx_tbl = qlcnic_83xx_mbx_tbl;
+       size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
+       for (i = 0; i < size; i++) {
+               if (type == mbx_tbl[i].cmd) {
+                       mbx->req.num = mbx_tbl[i].in_args;
+                       mbx->rsp.num = mbx_tbl[i].out_args;
+                       mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
+                                              GFP_ATOMIC);
+                       if (!mbx->req.arg)
+                               return -ENOMEM;
+                       mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),
+                                              GFP_ATOMIC);
+                       if (!mbx->rsp.arg) {
+                               kfree(mbx->req.arg);
+                               mbx->req.arg = NULL;
+                               return -ENOMEM;
+                       }
+                       memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+                       memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+                       temp = adapter->ahw->fw_hal_version << 29;
+                       mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
+                       break;
+               }
+       }
+       return 0;
+}
+
+void qlcnic_83xx_idc_aen_work(struct work_struct *work)
+{
+       struct qlcnic_adapter *adapter;
+       struct qlcnic_cmd_args cmd;
+       int i, err = 0;
+
+       adapter = container_of(work, struct qlcnic_adapter, idc_aen_work.work);
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_IDC_ACK);
+
+       for (i = 1; i < QLC_83XX_MBX_AEN_CNT; i++)
+               cmd.req.arg[i] = adapter->ahw->mbox_aen[i];
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev,
+                        "%s: Mailbox IDC ACK failed.\n", __func__);
+       qlcnic_free_mbx_args(&cmd);
+}
+
+static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
+                                           u32 data[])
+{
+       dev_dbg(&adapter->pdev->dev, "Completion AEN:0x%x.\n",
+               QLCNIC_MBX_RSP(data[0]));
+       clear_bit(QLC_83XX_IDC_COMP_AEN, &adapter->ahw->idc.status);
+       return;
+}
+
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
+{
+       u32 mask, resp, event[QLC_83XX_MBX_AEN_CNT];
+       int i;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (!spin_trylock(&ahw->mbx_lock)) {
+               mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+               writel(0, adapter->ahw->pci_base0 + mask);
+               return;
+       }
+       resp = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
+
+       if (!(resp & QLCNIC_SET_OWNER))
+               goto out;
+
+       for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+               event[i] = readl(QLCNIC_MBX_FW(ahw, i));
+
+       switch (QLCNIC_MBX_RSP(event[0])) {
+
+       case QLCNIC_MBX_LINK_EVENT:
+               qlcnic_83xx_handle_link_aen(adapter, event);
+               break;
+       case QLCNIC_MBX_COMP_EVENT:
+               qlcnic_83xx_handle_idc_comp_aen(adapter, event);
+               break;
+       case QLCNIC_MBX_REQUEST_EVENT:
+               for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+                       adapter->ahw->mbox_aen[i] = QLCNIC_MBX_RSP(event[i]);
+               queue_delayed_work(adapter->qlcnic_wq,
+                                  &adapter->idc_aen_work, 0);
+               break;
+       case QLCNIC_MBX_TIME_EXTEND_EVENT:
+               break;
+       case QLCNIC_MBX_SFP_INSERT_EVENT:
+               dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",
+                        QLCNIC_MBX_RSP(event[0]));
+               break;
+       case QLCNIC_MBX_SFP_REMOVE_EVENT:
+               dev_info(&adapter->pdev->dev, "SFP Removed AEN:0x%x.\n",
+                        QLCNIC_MBX_RSP(event[0]));
+               break;
+       default:
+               dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n",
+                       QLCNIC_MBX_RSP(event[0]));
+               break;
+       }
+
+       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+out:
+       mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+       writel(0, adapter->ahw->pci_base0 + mask);
+       spin_unlock(&ahw->mbx_lock);
+}
+
+static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)
+{
+       int index, i, err, sds_mbx_size;
+       u32 *buf, intrpt_id, intr_mask;
+       u16 context_id;
+       u8 num_sds;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_host_sds_ring *sds;
+       struct qlcnic_sds_mbx sds_mbx;
+       struct qlcnic_add_rings_mbx_out *mbx_out;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+       context_id = recv_ctx->context_id;
+       num_sds = (adapter->max_sds_rings - QLCNIC_MAX_RING_SETS);
+       ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                   QLCNIC_CMD_ADD_RCV_RINGS);
+       cmd.req.arg[1] = 0 | (num_sds << 8) | (context_id << 16);
+
+       /* set up status rings, mbx 2-81 */
+       index = 2;
+       for (i = 8; i < adapter->max_sds_rings; i++) {
+               memset(&sds_mbx, 0, sds_mbx_size);
+               sds = &recv_ctx->sds_rings[i];
+               sds->consumer = 0;
+               memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+               sds_mbx.phy_addr = sds->phys_addr;
+               sds_mbx.sds_ring_size = sds->num_desc;
+
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intrpt_id = ahw->intr_tbl[i].id;
+               else
+                       intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+
+               if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+                       sds_mbx.intrpt_id = intrpt_id;
+               else
+                       sds_mbx.intrpt_id = 0xffff;
+               sds_mbx.intrpt_val = 0;
+               buf = &cmd.req.arg[index];
+               memcpy(buf, &sds_mbx, sds_mbx_size);
+               index += sds_mbx_size / sizeof(u32);
+       }
+
+       /* send the mailbox command */
+       err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to add rings %d\n", err);
+               goto out;
+       }
+
+       mbx_out = (struct qlcnic_add_rings_mbx_out *)&cmd.rsp.arg[1];
+       index = 0;
+       /* status descriptor ring */
+       for (i = 8; i < adapter->max_sds_rings; i++) {
+               sds = &recv_ctx->sds_rings[i];
+               sds->crb_sts_consumer = ahw->pci_base0 +
+                                       mbx_out->host_csmr[index];
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intr_mask = ahw->intr_tbl[i].src;
+               else
+                       intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+
+               sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+               index++;
+       }
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+       int i, err, index, sds_mbx_size, rds_mbx_size;
+       u8 num_sds, num_rds;
+       u32 *buf, intrpt_id, intr_mask, cap = 0;
+       struct qlcnic_host_sds_ring *sds;
+       struct qlcnic_host_rds_ring *rds;
+       struct qlcnic_sds_mbx sds_mbx;
+       struct qlcnic_rds_mbx rds_mbx;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_rcv_mbx_out *mbx_out;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       num_rds = adapter->max_rds_rings;
+
+       if (adapter->max_sds_rings <= QLCNIC_MAX_RING_SETS)
+               num_sds = adapter->max_sds_rings;
+       else
+               num_sds = QLCNIC_MAX_RING_SETS;
+
+       sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+       rds_mbx_size = sizeof(struct qlcnic_rds_mbx);
+       cap = QLCNIC_CAP0_LEGACY_CONTEXT;
+
+       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+               cap |= QLC_83XX_FW_CAP_LRO_MSS;
+
+       /* set mailbox hdr and capabilities */
+       qlcnic_alloc_mbx_args(&cmd, adapter,
+                             QLCNIC_CMD_CREATE_RX_CTX);
+       cmd.req.arg[1] = cap;
+       cmd.req.arg[5] = 1 | (num_rds << 5) | (num_sds << 8) |
+                        (QLC_83XX_HOST_RDS_MODE_UNIQUE << 16);
+       /* set up status rings, mbx 8-57/87 */
+       index = QLC_83XX_HOST_SDS_MBX_IDX;
+       for (i = 0; i < num_sds; i++) {
+               memset(&sds_mbx, 0, sds_mbx_size);
+               sds = &recv_ctx->sds_rings[i];
+               sds->consumer = 0;
+               memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+               sds_mbx.phy_addr = sds->phys_addr;
+               sds_mbx.sds_ring_size = sds->num_desc;
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intrpt_id = ahw->intr_tbl[i].id;
+               else
+                       intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+               if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+                       sds_mbx.intrpt_id = intrpt_id;
+               else
+                       sds_mbx.intrpt_id = 0xffff;
+               sds_mbx.intrpt_val = 0;
+               buf = &cmd.req.arg[index];
+               memcpy(buf, &sds_mbx, sds_mbx_size);
+               index += sds_mbx_size / sizeof(u32);
+       }
+       /* set up receive rings, mbx 88-111/135 */
+       index = QLCNIC_HOST_RDS_MBX_IDX;
+       rds = &recv_ctx->rds_rings[0];
+       rds->producer = 0;
+       memset(&rds_mbx, 0, rds_mbx_size);
+       rds_mbx.phy_addr_reg = rds->phys_addr;
+       rds_mbx.reg_ring_sz = rds->dma_size;
+       rds_mbx.reg_ring_len = rds->num_desc;
+       /* Jumbo ring */
+       rds = &recv_ctx->rds_rings[1];
+       rds->producer = 0;
+       rds_mbx.phy_addr_jmb = rds->phys_addr;
+       rds_mbx.jmb_ring_sz = rds->dma_size;
+       rds_mbx.jmb_ring_len = rds->num_desc;
+       buf = &cmd.req.arg[index];
+       memcpy(buf, &rds_mbx, rds_mbx_size);
+
+       /* send the mailbox command */
+       err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to create Rx ctx in firmware%d\n", err);
+               goto out;
+       }
+       mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd.rsp.arg[1];
+       recv_ctx->context_id = mbx_out->ctx_id;
+       recv_ctx->state = mbx_out->state;
+       recv_ctx->virt_port = mbx_out->vport_id;
+       dev_info(&adapter->pdev->dev, "Rx Context[%d] Created, state:0x%x\n",
+                recv_ctx->context_id, recv_ctx->state);
+       /* Receive descriptor ring */
+       /* Standard ring */
+       rds = &recv_ctx->rds_rings[0];
+       rds->crb_rcv_producer = ahw->pci_base0 +
+                               mbx_out->host_prod[0].reg_buf;
+       /* Jumbo ring */
+       rds = &recv_ctx->rds_rings[1];
+       rds->crb_rcv_producer = ahw->pci_base0 +
+                               mbx_out->host_prod[0].jmb_buf;
+       /* status descriptor ring */
+       for (i = 0; i < num_sds; i++) {
+               sds = &recv_ctx->sds_rings[i];
+               sds->crb_sts_consumer = ahw->pci_base0 +
+                                       mbx_out->host_csmr[i];
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intr_mask = ahw->intr_tbl[i].src;
+               else
+                       intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+               sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+       }
+
+       if (adapter->max_sds_rings > QLCNIC_MAX_RING_SETS)
+               err = qlcnic_83xx_add_rings(adapter);
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
+                             struct qlcnic_host_tx_ring *tx, int ring)
+{
+       int err;
+       u16 msix_id;
+       u32 *buf, intr_mask;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_tx_mbx mbx;
+       struct qlcnic_tx_mbx_out *mbx_out;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Reset host resources */
+       tx->producer = 0;
+       tx->sw_consumer = 0;
+       *(tx->hw_consumer) = 0;
+
+       memset(&mbx, 0, sizeof(struct qlcnic_tx_mbx));
+
+       /* setup mailbox inbox registerss */
+       mbx.phys_addr = tx->phys_addr;
+       mbx.cnsmr_index = tx->hw_cons_phys_addr;
+       mbx.size = tx->num_desc;
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               msix_id = ahw->intr_tbl[adapter->max_sds_rings + ring].id;
+       else
+               msix_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+       if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+               mbx.intr_id = msix_id;
+       else
+               mbx.intr_id = 0xffff;
+       mbx.src = 0;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+       cmd.req.arg[1] = QLCNIC_CAP0_LEGACY_CONTEXT;
+       cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES;
+       buf = &cmd.req.arg[6];
+       memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx));
+       /* send the mailbox command*/
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to create Tx ctx in firmware 0x%x\n", err);
+               goto out;
+       }
+       mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2];
+       tx->crb_cmd_producer = ahw->pci_base0 + mbx_out->host_prod;
+       tx->ctx_id = mbx_out->ctx_id;
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               intr_mask = ahw->intr_tbl[adapter->max_sds_rings + ring].src;
+               tx->crb_intr_mask = ahw->pci_base0 + intr_mask;
+       }
+       dev_info(&adapter->pdev->dev, "Tx Context[0x%x] Created, state:0x%x\n",
+                tx->ctx_id, mbx_out->state);
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,
+                          u32 beacon)
+{
+       struct qlcnic_cmd_args cmd;
+       u32 mbx_in;
+       int i, status = 0;
+
+       if (state) {
+               /* Get LED configuration */
+               qlcnic_alloc_mbx_args(&cmd, adapter,
+                                     QLCNIC_CMD_GET_LED_CONFIG);
+               status = qlcnic_issue_cmd(adapter, &cmd);
+               if (status) {
+                       dev_err(&adapter->pdev->dev,
+                               "Get led config failed.\n");
+                       goto mbx_err;
+               } else {
+                       for (i = 0; i < 4; i++)
+                               adapter->ahw->mbox_reg[i] = cmd.rsp.arg[i+1];
+               }
+               qlcnic_free_mbx_args(&cmd);
+               /* Set LED Configuration */
+               mbx_in = (LSW(QLC_83XX_LED_CONFIG) << 16) |
+                         LSW(QLC_83XX_LED_CONFIG);
+               qlcnic_alloc_mbx_args(&cmd, adapter,
+                                     QLCNIC_CMD_SET_LED_CONFIG);
+               cmd.req.arg[1] = mbx_in;
+               cmd.req.arg[2] = mbx_in;
+               cmd.req.arg[3] = mbx_in;
+               if (beacon)
+                       cmd.req.arg[4] = QLC_83XX_ENABLE_BEACON;
+               status = qlcnic_issue_cmd(adapter, &cmd);
+               if (status) {
+                       dev_err(&adapter->pdev->dev,
+                               "Set led config failed.\n");
+               }
+mbx_err:
+               qlcnic_free_mbx_args(&cmd);
+               return status;
+
+       } else {
+               /* Restoring default LED configuration */
+               qlcnic_alloc_mbx_args(&cmd, adapter,
+                                     QLCNIC_CMD_SET_LED_CONFIG);
+               cmd.req.arg[1] = adapter->ahw->mbox_reg[0];
+               cmd.req.arg[2] = adapter->ahw->mbox_reg[1];
+               cmd.req.arg[3] = adapter->ahw->mbox_reg[2];
+               if (beacon)
+                       cmd.req.arg[4] = adapter->ahw->mbox_reg[3];
+               status = qlcnic_issue_cmd(adapter, &cmd);
+               if (status)
+                       dev_err(&adapter->pdev->dev,
+                               "Restoring led config failed.\n");
+               qlcnic_free_mbx_args(&cmd);
+               return status;
+       }
+}
+
+void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter,
+                                      int enable)
+{
+       struct qlcnic_cmd_args cmd;
+       int status;
+
+       if (enable) {
+               qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INIT_NIC_FUNC);
+               cmd.req.arg[1] = 1 | BIT_0;
+       } else {
+               qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+               cmd.req.arg[1] = 0 | BIT_0;
+       }
+       status = qlcnic_issue_cmd(adapter, &cmd);
+       if (status)
+               dev_err(&adapter->pdev->dev,
+                       "Failed to %s in NIC IDC function event.\n",
+                       (enable ? "register" : "unregister"));
+
+       qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_args cmd;
+       int err;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORT_CONFIG);
+       cmd.req.arg[1] = adapter->ahw->port_config;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev, "Set Port Config failed.\n");
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_args cmd;
+       int err;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PORT_CONFIG);
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev, "Get Port config failed\n");
+       else
+               adapter->ahw->port_config = cmd.rsp.arg[1];
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable)
+{
+       int err;
+       u32 temp;
+       struct qlcnic_cmd_args cmd;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_EVENT);
+       temp = adapter->recv_ctx->context_id << 16;
+       cmd.req.arg[1] = (enable ? 1 : 0) | BIT_8 | temp;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev,
+                        "Setup linkevent mailbox failed\n");
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+{
+       int err;
+       u32 temp;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return -EIO;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
+       temp = adapter->recv_ctx->context_id << 16;
+       cmd.req.arg[1] = (mode ? 1 : 0) | temp;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev,
+                        "Promiscous mode config failed\n");
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0, loop = 0;
+       u32 config;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status)
+               return status;
+
+       config = ahw->port_config;
+       set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+
+       if (mode == QLCNIC_ILB_MODE)
+               ahw->port_config |= QLC_83XX_CFG_LOOPBACK_HSS;
+       if (mode == QLCNIC_ELB_MODE)
+               ahw->port_config |= QLC_83XX_CFG_LOOPBACK_EXT;
+
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to Set Loopback Mode = 0x%x.\n",
+                       ahw->port_config);
+               ahw->port_config = config;
+               clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+               return status;
+       }
+
+       /* Wait until firmware send IDC Completion AEN */
+       do {
+               msleep(300);
+               if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+                       dev_err(&adapter->pdev->dev,
+                               "FW did not generate IDC completion AEN\n");
+                       clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+                       return -EIO;
+               }
+       } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+       qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+                                 QLCNIC_MAC_ADD);
+       return status;
+}
+
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0, loop = 0;
+       u32 config = ahw->port_config;
+
+       set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+       if (mode == QLCNIC_ILB_MODE)
+               ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_HSS;
+       if (mode == QLCNIC_ELB_MODE)
+               ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_EXT;
+
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to Clear Loopback Mode = 0x%x.\n",
+                       ahw->port_config);
+               ahw->port_config = config;
+               clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+               return status;
+       }
+
+       /* Wait until firmware send IDC Completion AEN */
+       do {
+               msleep(300);
+               if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+                       dev_err(&adapter->pdev->dev,
+                               "Firmware didn't sent IDC completion AEN\n");
+                       clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+                       return -EIO;
+               }
+       } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+       qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+                                 QLCNIC_MAC_DEL);
+       return status;
+}
+
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip,
+                              int mode)
+{
+       int err;
+       u32 temp;
+       struct qlcnic_cmd_args cmd;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_IP_ADDR);
+       if (mode == QLCNIC_IP_UP) {
+               temp = adapter->recv_ctx->context_id << 16;
+               cmd.req.arg[1] = 1 | temp;
+       } else {
+               temp = adapter->recv_ctx->context_id << 16;
+               cmd.req.arg[1] = 2 | temp;
+       }
+       cmd.req.arg[2] = ntohl(ip);
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err != QLCNIC_RCODE_SUCCESS)
+               dev_err(&adapter->netdev->dev,
+                       "could not notify %s IP 0x%x request\n",
+                       (mode == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
+       qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *adapter, int mode)
+{
+       int err;
+       u32 temp, arg1;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return 0;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_HW_LRO);
+       temp = adapter->recv_ctx->context_id << 16;
+       arg1 = (mode ? (BIT_0 | BIT_1 | BIT_3) : 0) | temp;
+       cmd.req.arg[1] = arg1;
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev, "LRO config failed\n");
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+       int err;
+       u32 word;
+       struct qlcnic_cmd_args cmd;
+       const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+                           0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+                           0x255b0ec26d5a56daULL };
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_RSS);
+
+       /*
+        * RSS request:
+        * bits 3-0: Rsvd
+        *      5-4: hash_type_ipv4
+        *      7-6: hash_type_ipv6
+        *        8: enable
+        *        9: use indirection table
+        *    16-31: indirection table mask
+        */
+       word =  ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+               ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+               ((u32)(enable & 0x1) << 8) |
+               ((0x7ULL) << 16);
+       cmd.req.arg[1] = (adapter->recv_ctx->context_id);
+       cmd.req.arg[2] = word;
+       memcpy(&cmd.req.arg[4], key, sizeof(key));
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+
+       if (err)
+               dev_info(&adapter->pdev->dev, "RSS config failed\n");
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+
+}
+
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+                                  __le16 vlan_id, u8 op)
+{
+       int err;
+       u32 *buf;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_macvlan_mbx mv;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return -EIO;
+
+       err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
+       if (err)
+               return err;
+       cmd.req.arg[1] = op | (1 << 8) |
+                       (adapter->recv_ctx->context_id << 16);
+
+       mv.vlan = le16_to_cpu(vlan_id);
+       memcpy(&mv.mac, addr, ETH_ALEN);
+       buf = &cmd.req.arg[2];
+       memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_err(&adapter->pdev->dev,
+                       "MAC-VLAN %s to CAM failed, err=%d.\n",
+                       ((op == 1) ? "add " : "delete "), err);
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
+                                 __le16 vlan_id)
+{
+       u8 mac[ETH_ALEN];
+       memcpy(&mac, addr, ETH_ALEN);
+       qlcnic_83xx_sre_macaddr_change(adapter, mac, vlan_id, QLCNIC_MAC_ADD);
+}
+
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac,
+                              u8 type, struct qlcnic_cmd_args *cmd)
+{
+       switch (type) {
+       case QLCNIC_SET_STATION_MAC:
+       case QLCNIC_SET_FAC_DEF_MAC:
+               memcpy(&cmd->req.arg[2], mac, sizeof(u32));
+               memcpy(&cmd->req.arg[3], &mac[4], sizeof(u16));
+               break;
+       }
+       cmd->req.arg[1] = type;
+}
+
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+       int err, i;
+       struct qlcnic_cmd_args cmd;
+       u32 mac_low, mac_high;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+       qlcnic_83xx_configure_mac(adapter, mac, QLCNIC_GET_CURRENT_MAC, &cmd);
+       err = qlcnic_issue_cmd(adapter, &cmd);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               mac_low = cmd.rsp.arg[1];
+               mac_high = cmd.rsp.arg[2];
+
+               for (i = 0; i < 2; i++)
+                       mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+               for (i = 2; i < 6; i++)
+                       mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+       } else {
+               dev_err(&adapter->pdev->dev, "Failed to get mac address%d\n",
+                       err);
+               err = -EIO;
+       }
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
+{
+       int err;
+       u32 temp;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);
+       cmd.req.arg[1] = 1 | (adapter->recv_ctx->context_id << 16);
+       cmd.req.arg[3] = coal->flag;
+       temp = coal->rx_time_us << 16;
+       cmd.req.arg[2] = coal->rx_packets | temp;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err != QLCNIC_RCODE_SUCCESS)
+               dev_info(&adapter->pdev->dev,
+                        "Failed to send interrupt coalescence parameters\n");
+       qlcnic_free_mbx_args(&cmd);
+}
+
+static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
+                                       u32 data[])
+{
+       u8 link_status, duplex;
+       /* link speed */
+       link_status = LSB(data[3]) & 1;
+       adapter->ahw->link_speed = MSW(data[2]);
+       adapter->ahw->link_autoneg = MSB(MSW(data[3]));
+       adapter->ahw->module_type = MSB(LSW(data[3]));
+       duplex = LSB(MSW(data[3]));
+       if (duplex)
+               adapter->ahw->link_duplex = DUPLEX_FULL;
+       else
+               adapter->ahw->link_duplex = DUPLEX_HALF;
+       adapter->ahw->has_link_events = 1;
+       qlcnic_advert_link_change(adapter, link_status);
+}
+
+irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
+{
+       struct qlcnic_adapter *adapter = data;
+       qlcnic_83xx_process_aen(adapter);
+       return IRQ_HANDLED;
+}
+
+int qlcnic_enable_eswitch(struct qlcnic_adapter *adapter, u8 port, u8 enable)
+{
+       int err = -EIO;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Error, invoked by non management func\n",
+                       __func__);
+               return err;
+       }
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH);
+       cmd.req.arg[1] = (port & 0xf) | BIT_4;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev, "Failed to enable eswitch%d\n",
+                       err);
+               err = -EIO;
+       }
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+
+}
+
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter,
+                            struct qlcnic_info *nic)
+{
+       int i, err = -EIO;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Error, invoked by non management func\n",
+                       __func__);
+               return err;
+       }
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+       cmd.req.arg[1] = (nic->pci_func << 16);
+       cmd.req.arg[2] = 0x1 << 16;
+       cmd.req.arg[3] = nic->phys_port | (nic->switch_mode << 16);
+       cmd.req.arg[4] = nic->capabilities;
+       cmd.req.arg[5] = (nic->max_mac_filters & 0xFF) | ((nic->max_mtu) << 16);
+       cmd.req.arg[6] = (nic->max_tx_ques) | ((nic->max_rx_ques) << 16);
+       cmd.req.arg[7] = (nic->min_tx_bw) | ((nic->max_tx_bw) << 16);
+       for (i = 8; i < 32; i++)
+               cmd.req.arg[i] = 0;
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev, "Failed to set nic info%d\n",
+                       err);
+               err = -EIO;
+       }
+
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,
+                            struct qlcnic_info *npar_info, u8 func_id)
+{
+       int err;
+       u32 temp;
+       u8 op = 0;
+       struct qlcnic_cmd_args cmd;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+       if (func_id != adapter->ahw->pci_func) {
+               temp = func_id << 16;
+               cmd.req.arg[1] = op | BIT_31 | temp;
+       } else {
+               cmd.req.arg[1] = adapter->ahw->pci_func << 16;
+       }
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                        "Failed to get nic info %d\n", err);
+               goto out;
+       }
+
+       npar_info->op_type = cmd.rsp.arg[1];
+       npar_info->pci_func = cmd.rsp.arg[2] & 0xFFFF;
+       npar_info->op_mode = (cmd.rsp.arg[2] & 0xFFFF0000) >> 16;
+       npar_info->phys_port = cmd.rsp.arg[3] & 0xFFFF;
+       npar_info->switch_mode = (cmd.rsp.arg[3] & 0xFFFF0000) >> 16;
+       npar_info->capabilities = cmd.rsp.arg[4];
+       npar_info->max_mac_filters = cmd.rsp.arg[5] & 0xFF;
+       npar_info->max_mtu = (cmd.rsp.arg[5] & 0xFFFF0000) >> 16;
+       npar_info->max_tx_ques = cmd.rsp.arg[6] & 0xFFFF;
+       npar_info->max_rx_ques = (cmd.rsp.arg[6] & 0xFFFF0000) >> 16;
+       npar_info->min_tx_bw = cmd.rsp.arg[7] & 0xFFFF;
+       npar_info->max_tx_bw = (cmd.rsp.arg[7] & 0xFFFF0000) >> 16;
+       if (cmd.rsp.arg[8] & 0x1)
+               npar_info->max_bw_reg_offset = (cmd.rsp.arg[8] & 0x7FFE) >> 1;
+       if (cmd.rsp.arg[8] & 0x10000) {
+               temp = (cmd.rsp.arg[8] & 0x7FFE0000) >> 17;
+               npar_info->max_linkspeed_reg_offset = temp;
+       }
+
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
+                            struct qlcnic_pci_info *pci_info)
+{
+       int i, err = 0, j = 0;
+       u32 temp;
+       struct qlcnic_cmd_args cmd;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+       err = qlcnic_issue_cmd(adapter, &cmd);
+
+       adapter->ahw->act_pci_func = 0;
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               pci_info->func_count = cmd.rsp.arg[1] & 0xFF;
+               dev_info(&adapter->pdev->dev,
+                        "%s: total functions = %d\n",
+                        __func__, pci_info->func_count);
+               for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) {
+                       pci_info->id = cmd.rsp.arg[i] & 0xFFFF;
+                       pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+                       i++;
+                       pci_info->type = cmd.rsp.arg[i] & 0xFFFF;
+                       if (pci_info->type == QLCNIC_TYPE_NIC)
+                               adapter->ahw->act_pci_func++;
+                       temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+                       pci_info->default_port = temp;
+                       i++;
+                       pci_info->tx_min_bw = cmd.rsp.arg[i] & 0xFFFF;
+                       temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+                       pci_info->tx_max_bw = temp;
+                       i = i + 2;
+                       memcpy(pci_info->mac, &cmd.rsp.arg[i], ETH_ALEN - 2);
+                       i++;
+                       memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);
+                       i = i + 3;
+
+                       dev_info(&adapter->pdev->dev, "%s:\n"
+                                "\tid = %d active = %d type = %d\n"
+                                "\tport = %d min bw = %d max bw = %d\n"
+                                "\tmac_addr =  %pM\n", __func__,
+                                pci_info->id, pci_info->active, pci_info->type,
+                                pci_info->default_port, pci_info->tx_min_bw,
+                                pci_info->tx_max_bw, pci_info->mac);
+               }
+       } else {
+               dev_err(&adapter->pdev->dev, "Failed to get PCI Info%d\n",
+                       err);
+               err = -EIO;
+       }
+
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)
+{
+       int i, index, err;
+       bool type;
+       u8 max_ints;
+       u32 val, temp;
+       struct qlcnic_cmd_args cmd;
+
+       max_ints = adapter->ahw->num_msix;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);
+       cmd.req.arg[1] = max_ints;
+       for (i = 0, index = 2; i < max_ints; i++) {
+               type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
+               val = type | (adapter->ahw->intr_tbl[i].type << 4);
+               if (adapter->ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
+                       val |= (adapter->ahw->intr_tbl[i].id << 16);
+               cmd.req.arg[index++] = val;
+       }
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to configure interrupts 0x%x\n", err);
+               goto out;
+       }
+
+       max_ints = cmd.rsp.arg[1];
+       for (i = 0, index = 2; i < max_ints; i++, index += 2) {
+               val = cmd.rsp.arg[index];
+               if (LSB(val)) {
+                       dev_info(&adapter->pdev->dev,
+                                "Can't configure interrupt %d\n",
+                                adapter->ahw->intr_tbl[i].id);
+                       continue;
+               }
+               if (op_type) {
+                       adapter->ahw->intr_tbl[i].id = MSW(val);
+                       adapter->ahw->intr_tbl[i].enabled = 1;
+                       temp = cmd.rsp.arg[index + 1];
+                       adapter->ahw->intr_tbl[i].src = temp;
+               } else {
+                       adapter->ahw->intr_tbl[i].id = i;
+                       adapter->ahw->intr_tbl[i].enabled = 0;
+                       adapter->ahw->intr_tbl[i].src = 0;
+               }
+       }
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_lock_flash(struct qlcnic_adapter *adapter)
+{
+       int id, timeout = 0;
+       u32 status = 0;
+
+       while (status == 0) {
+               status = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
+               if (status)
+                       break;
+
+               if (++timeout >= QLC_83XX_FLASH_LOCK_TIMEOUT) {
+                       id = QLC_SHARED_REG_RD32(adapter,
+                                                QLCNIC_FLASH_LOCK_OWNER);
+                       dev_err(&adapter->pdev->dev,
+                               "%s: failed, lock held by %d\n", __func__, id);
+                       return -EIO;
+               }
+               usleep_range(1000, 2000);
+       }
+
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, adapter->portnum);
+       return 0;
+}
+
+void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *adapter)
+{
+       QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, 0xFF);
+}
+
+int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
+                                     u32 flash_addr, u8 *p_data,
+                                     int count)
+{
+       int i, ret;
+       u32 word, range, flash_offset, addr = flash_addr;
+       ulong indirect_add, direct_window;
+
+       flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);
+       if (addr & 0x3) {
+               dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+               return -EIO;
+       }
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_DIRECT_WINDOW,
+                                    (addr));
+
+       range = flash_offset + (count * sizeof(u32));
+       /* Check if data is spread across multiple sectors */
+       if (range > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+
+               /* Multi sector read */
+               for (i = 0; i < count; i++) {
+                       indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
+                       ret = qlcnic_83xx_rd_reg_indirect(adapter,
+                                                         indirect_add);
+                       if (ret == -EIO)
+                               return -EIO;
+
+                       word = ret;
+                       *(u32 *)p_data  = word;
+                       p_data = p_data + 4;
+                       addr = addr + 4;
+                       flash_offset = flash_offset + 4;
+
+                       if (flash_offset > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+                               direct_window = QLC_83XX_FLASH_DIRECT_WINDOW;
+                               /* This write is needed once for each sector */
+                               qlcnic_83xx_wrt_reg_indirect(adapter,
+                                                            direct_window,
+                                                            (addr));
+                               flash_offset = 0;
+                       }
+               }
+       } else {
+               /* Single sector read */
+               for (i = 0; i < count; i++) {
+                       indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
+                       ret = qlcnic_83xx_rd_reg_indirect(adapter,
+                                                         indirect_add);
+                       if (ret == -EIO)
+                               return -EIO;
+
+                       word = ret;
+                       *(u32 *)p_data  = word;
+                       p_data = p_data + 4;
+                       addr = addr + 4;
+               }
+       }
+
+       return 0;
+}
+
+static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+       u32 status;
+       int retries = QLC_83XX_FLASH_READ_RETRY_COUNT;
+
+       do {
+               status = qlcnic_83xx_rd_reg_indirect(adapter,
+                                                    QLC_83XX_FLASH_STATUS);
+               if ((status & QLC_83XX_FLASH_STATUS_READY) ==
+                   QLC_83XX_FLASH_STATUS_READY)
+                       break;
+
+               msleep(QLC_83XX_FLASH_STATUS_REG_POLL_DELAY);
+       } while (--retries);
+
+       if (!retries)
+               return -EIO;
+
+       return 0;
+}
+
+static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+       int ret;
+       u32 cmd;
+       cmd = adapter->ahw->fdt.write_statusreg_cmd;
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                    (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG | cmd));
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+                                    adapter->ahw->fdt.write_enable_bits);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret)
+               return -EIO;
+
+       return 0;
+}
+
+static int qlcnic_83xx_disable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+       int ret;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                    (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG |
+                                    adapter->ahw->fdt.write_statusreg_cmd));
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+                                    adapter->ahw->fdt.write_disable_bits);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret)
+               return -EIO;
+
+       return 0;
+}
+
+int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
+{
+       int ret, mfg_id;
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                    QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_READ_CTRL);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               qlcnic_83xx_unlock_flash(adapter);
+               return -EIO;
+       }
+
+       mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
+       if (mfg_id == -EIO)
+               return -EIO;
+
+       adapter->flash_mfg_id = (mfg_id & 0xFF);
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return 0;
+}
+
+int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter)
+{
+       int count, fdt_size, ret = 0;
+
+       fdt_size = sizeof(struct qlcnic_fdt);
+       count = fdt_size / sizeof(u32);
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       memset(&adapter->ahw->fdt, 0, fdt_size);
+       ret = qlcnic_83xx_lockless_flash_read32(adapter, QLCNIC_FDT_LOCATION,
+                                               (u8 *)&adapter->ahw->fdt,
+                                               count);
+
+       qlcnic_83xx_unlock_flash(adapter);
+       return ret;
+}
+
+int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
+                                  u32 sector_start_addr)
+{
+       u32 reversed_addr, addr1, addr2, cmd;
+       int ret = -EIO;
+
+       if (qlcnic_83xx_lock_flash(adapter) != 0)
+               return -EIO;
+
+       if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_enable_flash_write_op(adapter);
+               if (ret) {
+                       qlcnic_83xx_unlock_flash(adapter);
+                       dev_err(&adapter->pdev->dev,
+                               "%s failed at %d\n",
+                               __func__, __LINE__);
+                       return ret;
+               }
+       }
+
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               qlcnic_83xx_unlock_flash(adapter);
+               dev_err(&adapter->pdev->dev,
+                       "%s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       addr1 = (sector_start_addr & 0xFF) << 16;
+       addr2 = (sector_start_addr & 0xFF0000) >> 16;
+       reversed_addr = addr1 | addr2;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+                                    reversed_addr);
+       cmd = QLC_83XX_FLASH_FDT_ERASE_DEF_SIG | adapter->ahw->fdt.erase_cmd;
+       if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id)
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, cmd);
+       else
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                            QLC_83XX_FLASH_OEM_ERASE_SIG);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               qlcnic_83xx_unlock_flash(adapter);
+               dev_err(&adapter->pdev->dev,
+                       "%s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_disable_flash_write_op(adapter);
+               if (ret) {
+                       qlcnic_83xx_unlock_flash(adapter);
+                       dev_err(&adapter->pdev->dev,
+                               "%s: failed at %d\n", __func__, __LINE__);
+                       return ret;
+               }
+       }
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return 0;
+}
+
+int qlcnic_83xx_flash_write32(struct qlcnic_adapter *adapter, u32 addr,
+                             u32 *p_data)
+{
+       int ret = -EIO;
+       u32 addr1 = 0x00800000 | (addr >> 2);
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, addr1);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
+                                u32 *p_data, int count)
+{
+       u32 temp;
+       int ret = -EIO;
+
+       if ((count < QLC_83XX_FLASH_BULK_WRITE_MIN) ||
+           (count > QLC_83XX_FLASH_BULK_WRITE_MAX)) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Invalid word count\n", __func__);
+               return -EIO;
+       }
+
+       temp = qlcnic_83xx_rd_reg_indirect(adapter,
+                                          QLC_83XX_FLASH_SPI_CONTROL);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL,
+                                    (temp | QLC_83XX_FLASH_SPI_CTRL));
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                    QLC_83XX_FLASH_ADDR_TEMP_VAL);
+
+       /* First DWORD write */
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_FIRST_MS_PATTERN);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       count--;
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                    QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL);
+       /* Second to N-1 DWORD writes */
+       while (count != 1) {
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+                                            *p_data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                            QLC_83XX_FLASH_SECOND_MS_PATTERN);
+               ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+               if (ret) {
+                       dev_err(&adapter->pdev->dev,
+                               "%s: failed at %d\n", __func__, __LINE__);
+                       return -EIO;
+               }
+               count--;
+       }
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                    QLC_83XX_FLASH_ADDR_TEMP_VAL |
+                                    (addr >> 2));
+       /* Last DWORD write */
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_LAST_MS_PATTERN);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS);
+       if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) {
+               dev_err(&adapter->pdev->dev, "%s: failed at %d\n",
+                       __func__, __LINE__);
+               /* Operation failed, clear error bit */
+               temp = qlcnic_83xx_rd_reg_indirect(adapter,
+                                                  QLC_83XX_FLASH_SPI_CONTROL);
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                                            QLC_83XX_FLASH_SPI_CONTROL,
+                                            (temp | QLC_83XX_FLASH_SPI_CTRL));
+       }
+
+       return 0;
+}
+
+static void qlcnic_83xx_recover_driver_lock(struct qlcnic_adapter *adapter)
+{
+       u32 val, id;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+
+       /* Check if recovery need to be performed by the calling function */
+       if ((val & QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK) == 0) {
+               val = val & ~0x3F;
+               val = val | ((adapter->portnum << 2) |
+                            QLC_83XX_NEED_DRV_LOCK_RECOVERY);
+               QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+               dev_info(&adapter->pdev->dev,
+                        "%s: lock recovery initiated\n", __func__);
+               msleep(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
+               val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+               id = ((val >> 2) & 0xF);
+               if (id == adapter->portnum) {
+                       val = val & ~QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK;
+                       val = val | QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS;
+                       QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+                       /* Force release the lock */
+                       QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+                       /* Clear recovery bits */
+                       val = val & ~0x3F;
+                       QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+                       dev_info(&adapter->pdev->dev,
+                                "%s: lock recovery completed\n", __func__);
+               } else {
+                       dev_info(&adapter->pdev->dev,
+                                "%s: func %d to resume lock recovery process\n",
+                                __func__, id);
+               }
+       } else {
+               dev_info(&adapter->pdev->dev,
+                        "%s: lock recovery initiated by other functions\n",
+                        __func__);
+       }
+}
+
+int qlcnic_83xx_lock_driver(struct qlcnic_adapter *adapter)
+{
+       u32 lock_alive_counter, val, id, i = 0, status = 0, temp = 0;
+       int max_attempt = 0;
+
+       while (status == 0) {
+               status = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK);
+               if (status)
+                       break;
+
+               msleep(QLC_83XX_DRV_LOCK_WAIT_DELAY);
+               i++;
+
+               if (i == 1)
+                       temp = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+
+               if (i == QLC_83XX_DRV_LOCK_WAIT_COUNTER) {
+                       val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+                       if (val == temp) {
+                               id = val & 0xFF;
+                               dev_info(&adapter->pdev->dev,
+                                        "%s: lock to be recovered from %d\n",
+                                        __func__, id);
+                               qlcnic_83xx_recover_driver_lock(adapter);
+                               i = 0;
+                               max_attempt++;
+                       } else {
+                               dev_err(&adapter->pdev->dev,
+                                       "%s: failed to get lock\n", __func__);
+                               return -EIO;
+                       }
+               }
+
+               /* Force exit from while loop after few attempts */
+               if (max_attempt == QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT) {
+                       dev_err(&adapter->pdev->dev,
+                               "%s: failed to get lock\n", __func__);
+                       return -EIO;
+               }
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+       lock_alive_counter = val >> 8;
+       lock_alive_counter++;
+       val = lock_alive_counter << 8 | adapter->portnum;
+       QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+
+       return 0;
+}
+
+void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *adapter)
+{
+       u32 val, lock_alive_counter, id;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+       id = val & 0xFF;
+       lock_alive_counter = val >> 8;
+
+       if (id != adapter->portnum)
+               dev_err(&adapter->pdev->dev,
+                       "%s:Warning func %d is unlocking lock owned by %d\n",
+                       __func__, adapter->portnum, id);
+
+       val = (lock_alive_counter << 8) | 0xFF;
+       QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+       QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+}
+
+int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
+                               u32 *data, u32 count)
+{
+       int i, j, ret = 0;
+       u32 temp;
+
+       /* Check alignment */
+       if (addr & 0xF)
+               return -EIO;
+
+       mutex_lock(&adapter->ahw->mem_lock);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_HI, 0);
+
+       for (i = 0; i < count; i++, addr += 16) {
+               if (!((ADDR_IN_RANGE(addr, QLCNIC_ADDR_QDR_NET,
+                                    QLCNIC_ADDR_QDR_NET_MAX)) ||
+                     (ADDR_IN_RANGE(addr, QLCNIC_ADDR_DDR_NET,
+                                    QLCNIC_ADDR_DDR_NET_MAX)))) {
+                       mutex_unlock(&adapter->ahw->mem_lock);
+                       return -EIO;
+               }
+
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_LO, addr);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_LO,
+                                            *data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_HI,
+                                            *data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_ULO,
+                                            *data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_UHI,
+                                            *data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+                                            QLCNIC_TA_WRITE_ENABLE);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+                                            QLCNIC_TA_WRITE_START);
+
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = qlcnic_83xx_rd_reg_indirect(adapter,
+                                                          QLCNIC_MS_CTRL);
+                       if ((temp & TA_CTL_BUSY) == 0)
+                               break;
+               }
+
+               /* Status check failure */
+               if (j >= MAX_CTL_CHECK) {
+                       printk_ratelimited(KERN_WARNING
+                                          "MS memory write failed\n");
+                       mutex_unlock(&adapter->ahw->mem_lock);
+                       return -EIO;
+               }
+       }
+
+       mutex_unlock(&adapter->ahw->mem_lock);
+
+       return ret;
+}
+
+int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
+                            u8 *p_data, int count)
+{
+       int i, ret;
+       u32 word, addr = flash_addr;
+       ulong  indirect_addr;
+
+       if (qlcnic_83xx_lock_flash(adapter) != 0)
+               return -EIO;
+
+       if (addr & 0x3) {
+               dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+               qlcnic_83xx_unlock_flash(adapter);
+               return -EIO;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (qlcnic_83xx_wrt_reg_indirect(adapter,
+                                                QLC_83XX_FLASH_DIRECT_WINDOW,
+                                                (addr))) {
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+
+               indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
+               ret = qlcnic_83xx_rd_reg_indirect(adapter,
+                                                 indirect_addr);
+               if (ret == -EIO)
+                       return -EIO;
+               word = ret;
+               *p_data  = word;
+               p_data = p_data + 4;
+               addr = addr + 4;
+       }
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return 0;
+}
+
+int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
+{
+       int err;
+       u32 config = 0, state;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(ahw->pci_func));
+       if (!QLC_83xx_FUNC_VAL(state, ahw->pci_func)) {
+               dev_info(&adapter->pdev->dev, "link state down\n");
+               return config;
+       }
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                        "Get Link Status Command failed: 0x%x\n", err);
+               goto out;
+       } else {
+               config = cmd.rsp.arg[1];
+               switch (QLC_83XX_CURRENT_LINK_SPEED(config)) {
+               case QLC_83XX_10M_LINK:
+                       ahw->link_speed = SPEED_10;
+                       break;
+               case QLC_83XX_100M_LINK:
+                       ahw->link_speed = SPEED_100;
+                       break;
+               case QLC_83XX_1G_LINK:
+                       ahw->link_speed = SPEED_1000;
+                       break;
+               case QLC_83XX_10G_LINK:
+                       ahw->link_speed = SPEED_10000;
+                       break;
+               default:
+                       ahw->link_speed = 0;
+                       break;
+               }
+               config = cmd.rsp.arg[3];
+               if (config & 1)
+                       err = 1;
+       }
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return config;
+}
+
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter)
+{
+       u32 config = 0;
+       int status = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Get port configuration info */
+       status = qlcnic_83xx_get_port_info(adapter);
+       /* Get Link Status related info */
+       config = qlcnic_83xx_test_link(adapter);
+       ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
+       /* hard code until there is a way to get it from flash */
+       ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;
+       return status;
+}
+
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
+                            struct ethtool_cmd *ecmd)
+{
+       int status = 0;
+       u32 config = adapter->ahw->port_config;
+
+       if (ecmd->autoneg)
+               adapter->ahw->port_config |= BIT_15;
+
+       switch (ethtool_cmd_speed(ecmd)) {
+       case SPEED_10:
+               adapter->ahw->port_config |= BIT_8;
+               break;
+       case SPEED_100:
+               adapter->ahw->port_config |= BIT_9;
+               break;
+       case SPEED_1000:
+               adapter->ahw->port_config |= BIT_10;
+               break;
+       case SPEED_10000:
+               adapter->ahw->port_config |= BIT_11;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               dev_info(&adapter->pdev->dev,
+                        "Faild to Set Link Speed and autoneg.\n");
+               adapter->ahw->port_config = config;
+       }
+       return status;
+}
+
+static inline u64 *qlcnic_83xx_copy_stats(struct qlcnic_cmd_args *cmd,
+                                         u64 *data, int index)
+{
+       u32 low, hi;
+       u64 val;
+
+       low = cmd->rsp.arg[index];
+       hi = cmd->rsp.arg[index + 1];
+       val = (((u64) low) | (((u64) hi) << 32));
+       *data++ = val;
+       return data;
+}
+
+static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
+                                  struct qlcnic_cmd_args *cmd, u64 *data,
+                                  int type, int *ret)
+{
+       int err, k, total_regs;
+
+       *ret = 0;
+       err = qlcnic_issue_cmd(adapter, cmd);
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_info(&adapter->pdev->dev,
+                        "Error in get statistics mailbox command\n");
+               *ret = -EIO;
+               return data;
+       }
+       total_regs = cmd->rsp.num;
+       switch (type) {
+       case QLC_83XX_STAT_MAC:
+               /* fill in MAC tx counters */
+               for (k = 2; k < 28; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 24 bytes of reserved area */
+               /* fill in MAC rx counters */
+               for (k += 6; k < 60; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 24 bytes of reserved area */
+               /* fill in MAC rx frame stats */
+               for (k += 6; k < 80; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               break;
+       case QLC_83XX_STAT_RX:
+               for (k = 2; k < 8; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 8 bytes of reserved data */
+               for (k += 2; k < 24; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 8 bytes containing RE1FBQ error data */
+               for (k += 2; k < total_regs; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               break;
+       case QLC_83XX_STAT_TX:
+               for (k = 2; k < 10; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 8 bytes of reserved data */
+               for (k += 2; k < total_regs; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               break;
+       default:
+               dev_warn(&adapter->pdev->dev, "Unknown get statistics mode\n");
+               *ret = -EIO;
+       }
+       return data;
+}
+
+void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
+{
+       struct qlcnic_cmd_args cmd;
+       int ret = 0;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
+       /* Get Tx stats */
+       cmd.req.arg[1] = BIT_1 | (adapter->tx_ring->ctx_id << 16);
+       cmd.rsp.num = QLC_83XX_TX_STAT_REGS;
+       data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+                                     QLC_83XX_STAT_TX, &ret);
+       if (ret) {
+               dev_info(&adapter->pdev->dev, "Error getting MAC stats\n");
+               goto out;
+       }
+       /* Get MAC stats */
+       cmd.req.arg[1] = BIT_2 | (adapter->portnum << 16);
+       cmd.rsp.num = QLC_83XX_MAC_STAT_REGS;
+       memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+       data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+                                     QLC_83XX_STAT_MAC, &ret);
+       if (ret) {
+               dev_info(&adapter->pdev->dev,
+                        "Error getting Rx stats\n");
+               goto out;
+       }
+       /* Get Rx stats */
+       cmd.req.arg[1] = adapter->recv_ctx->context_id << 16;
+       cmd.rsp.num = QLC_83XX_RX_STAT_REGS;
+       memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+       data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+                                     QLC_83XX_STAT_RX, &ret);
+       if (ret)
+               dev_info(&adapter->pdev->dev,
+                        "Error getting Tx stats\n");
+out:
+       qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter)
+{
+       u32 major, minor, sub;
+
+       major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+       minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+       sub = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
+
+       if (adapter->fw_version != QLCNIC_VERSION_CODE(major, minor, sub)) {
+               dev_info(&adapter->pdev->dev, "%s: Reg test failed\n",
+                        __func__);
+               return 1;
+       }
+       return 0;
+}
+
+int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter)
+{
+       return (ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl) *
+               sizeof(adapter->ahw->ext_reg_tbl)) +
+               (ARRAY_SIZE(qlcnic_83xx_reg_tbl) +
+               sizeof(adapter->ahw->reg_tbl));
+}
+
+int qlcnic_83xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)
+{
+       int i, j = 0;
+
+       for (i = QLCNIC_DEV_INFO_SIZE + 1;
+            j < ARRAY_SIZE(qlcnic_83xx_reg_tbl); i++, j++)
+               regs_buff[i] = QLC_SHARED_REG_RD32(adapter, j);
+
+       for (j = 0; j < ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl); j++)
+               regs_buff[i++] = QLCRDX(adapter->ahw, j);
+       return i;
+}
+
+int qlcnic_83xx_interrupt_test(struct qlcnic_adapter *adapter,
+                              struct qlcnic_cmd_args *cmd)
+{
+       u8 val;
+       int ret;
+       u32 data;
+       u16 intrpt_id, id;
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               intrpt_id = adapter->ahw->intr_tbl[0].id;
+       else
+               intrpt_id = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_ID);
+
+       cmd->req.arg[1] = 1;
+       cmd->req.arg[2] = intrpt_id;
+       cmd->req.arg[3] = BIT_0;
+
+       ret = qlcnic_issue_cmd(adapter, cmd);
+       data = cmd->rsp.arg[2];
+       id = LSW(data);
+       val = LSB(MSW(data));
+       if (id != intrpt_id)
+               dev_info(&adapter->pdev->dev,
+                        "Interrupt generated: 0x%x, requested:0x%x\n",
+                        id, intrpt_id);
+       if (val)
+               dev_info(&adapter->pdev->dev,
+                        "Interrupt test error: 0x%x\n", val);
+
+       return ret;
+}
+
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *adapter,
+                               struct ethtool_pauseparam *pause)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0;
+       u32 config;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Get Pause Config failed\n", __func__);
+               return;
+       }
+       config = ahw->port_config;
+       if (config & QLC_83XX_CFG_STD_PAUSE) {
+               if (config & QLC_83XX_CFG_STD_TX_PAUSE)
+                       pause->tx_pause = 1;
+               if (config & QLC_83XX_CFG_STD_RX_PAUSE)
+                       pause->rx_pause = 1;
+       }
+
+       if (QLC_83XX_AUTONEG(config))
+               pause->autoneg = 1;
+}
+
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
+                              struct ethtool_pauseparam *pause)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0;
+       u32 config;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Get Pause Config failed.\n", __func__);
+               return status;
+       }
+       config = ahw->port_config;
+
+       if (ahw->port_type == QLCNIC_GBE) {
+               if (pause->autoneg)
+                       ahw->port_config |= QLC_83XX_ENABLE_AUTONEG;
+               if (!pause->autoneg)
+                       ahw->port_config &= ~QLC_83XX_ENABLE_AUTONEG;
+       } else if ((ahw->port_type == QLCNIC_XGBE) && (pause->autoneg)) {
+               return -EOPNOTSUPP;
+       }
+
+       if (!(config & QLC_83XX_CFG_STD_PAUSE))
+               ahw->port_config |= QLC_83XX_CFG_STD_PAUSE;
+
+       if (pause->rx_pause && pause->tx_pause) {
+               ahw->port_config |= QLC_83XX_CFG_STD_TX_RX_PAUSE;
+       } else if (pause->rx_pause && !pause->tx_pause) {
+               ahw->port_config &= ~QLC_83XX_CFG_STD_TX_PAUSE;
+               ahw->port_config |= QLC_83XX_CFG_STD_RX_PAUSE;
+       } else if (pause->tx_pause && !pause->rx_pause) {
+               ahw->port_config &= ~QLC_83XX_CFG_STD_RX_PAUSE;
+               ahw->port_config |= QLC_83XX_CFG_STD_TX_PAUSE;
+       } else if (!pause->rx_pause && !pause->tx_pause) {
+               ahw->port_config &= ~QLC_83XX_CFG_STD_TX_RX_PAUSE;
+       }
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Set Pause Config failed.\n", __func__);
+               ahw->port_config = config;
+       }
+       return status;
+}
+
+static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+       int ret;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                    QLC_83XX_FLASH_OEM_READ_SIG);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                                    QLC_83XX_FLASH_READ_CTRL);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret)
+               return -EIO;
+
+       ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
+       return ret & 0xFF;
+}
+
+int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
+{
+       int status;
+
+       status = qlcnic_83xx_read_flash_status_reg(adapter);
+       if (status == -EIO) {
+               dev_info(&adapter->pdev->dev, "%s: EEPROM test failed.\n",
+                        __func__);
+               return 1;
+       }
+       return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
new file mode 100644 (file)
index 0000000..2b44eb1
--- /dev/null
@@ -0,0 +1,424 @@
+#ifndef __QLCNIC_83XX_HW_H
+#define __QLCNIC_83XX_HW_H
+
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include "qlcnic_hw.h"
+
+/* Directly mapped registers */
+#define QLC_83XX_CRB_WIN_BASE          0x3800
+#define QLC_83XX_CRB_WIN_FUNC(f)       (QLC_83XX_CRB_WIN_BASE+((f)*4))
+#define QLC_83XX_SEM_LOCK_BASE         0x3840
+#define QLC_83XX_SEM_UNLOCK_BASE       0x3844
+#define QLC_83XX_SEM_LOCK_FUNC(f)      (QLC_83XX_SEM_LOCK_BASE+((f)*8))
+#define QLC_83XX_SEM_UNLOCK_FUNC(f)    (QLC_83XX_SEM_UNLOCK_BASE+((f)*8))
+#define QLC_83XX_LINK_STATE(f)         (0x3698+((f) > 7 ? 4 : 0))
+#define QLC_83XX_LINK_SPEED(f)         (0x36E0+(((f) >> 2) * 4))
+#define QLC_83XX_LINK_SPEED_FACTOR     10
+#define QLC_83xx_FUNC_VAL(v, f)        ((v) & (1 << (f * 4)))
+#define QLC_83XX_INTX_PTR              0x38C0
+#define QLC_83XX_INTX_TRGR             0x38C4
+#define QLC_83XX_INTX_MASK             0x38C8
+
+#define QLC_83XX_DRV_LOCK_WAIT_COUNTER                 100
+#define QLC_83XX_DRV_LOCK_WAIT_DELAY                   20
+#define QLC_83XX_NEED_DRV_LOCK_RECOVERY                1
+#define QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS         2
+#define QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT         3
+#define QLC_83XX_DRV_LOCK_RECOVERY_DELAY               200
+#define QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK         0x3
+
+#define QLC_83XX_NO_NIC_RESOURCE       0x5
+#define QLC_83XX_MAC_PRESENT           0xC
+#define QLC_83XX_MAC_ABSENT            0xD
+
+
+#define QLC_83XX_FLASH_SECTOR_SIZE             (64 * 1024)
+
+/* PEG status definitions */
+#define QLC_83XX_CMDPEG_COMPLETE               0xff01
+#define QLC_83XX_VALID_INTX_BIT30(val)         ((val) & BIT_30)
+#define QLC_83XX_VALID_INTX_BIT31(val)         ((val) & BIT_31)
+#define QLC_83XX_INTX_FUNC(val)                ((val) & 0xFF)
+#define QLC_83XX_LEGACY_INTX_MAX_RETRY         100
+#define QLC_83XX_LEGACY_INTX_DELAY             4
+#define QLC_83XX_REG_DESC                      1
+#define QLC_83XX_LRO_DESC                      2
+#define QLC_83XX_CTRL_DESC                     3
+#define QLC_83XX_FW_CAPABILITY_TSO             BIT_6
+#define QLC_83XX_FW_CAP_LRO_MSS                BIT_17
+#define QLC_83XX_HOST_RDS_MODE_UNIQUE          0
+#define QLC_83XX_HOST_SDS_MBX_IDX              8
+
+#define QLCNIC_HOST_RDS_MBX_IDX                        88
+#define QLCNIC_MAX_RING_SETS                   8
+
+/* Pause control registers */
+#define QLC_83XX_SRE_SHIM_REG          0x0D200284
+#define QLC_83XX_PORT0_THRESHOLD       0x0B2003A4
+#define QLC_83XX_PORT1_THRESHOLD       0x0B2013A4
+#define QLC_83XX_PORT0_TC_MC_REG       0x0B200388
+#define QLC_83XX_PORT1_TC_MC_REG       0x0B201388
+#define QLC_83XX_PORT0_TC_STATS                0x0B20039C
+#define QLC_83XX_PORT1_TC_STATS                0x0B20139C
+#define QLC_83XX_PORT2_IFB_THRESHOLD   0x0B200704
+#define QLC_83XX_PORT3_IFB_THRESHOLD   0x0B201704
+
+/* Peg PC status registers */
+#define QLC_83XX_CRB_PEG_NET_0         0x3400003c
+#define QLC_83XX_CRB_PEG_NET_1         0x3410003c
+#define QLC_83XX_CRB_PEG_NET_2         0x3420003c
+#define QLC_83XX_CRB_PEG_NET_3         0x3430003c
+#define QLC_83XX_CRB_PEG_NET_4         0x34b0003c
+
+/* Firmware image definitions */
+#define QLC_83XX_BOOTLOADER_FLASH_ADDR 0x10000
+#define QLC_83XX_FW_FILE_NAME          "83xx_fw.bin"
+#define QLC_83XX_BOOT_FROM_FLASH       0
+#define QLC_83XX_BOOT_FROM_FILE                0x12345678
+
+#define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16
+
+struct qlcnic_intrpt_config {
+       u8      type;
+       u8      enabled;
+       u16     id;
+       u32     src;
+};
+
+struct qlcnic_macvlan_mbx {
+       u8      mac[ETH_ALEN];
+       u16     vlan;
+};
+
+struct qlc_83xx_fw_info {
+       const struct firmware   *fw;
+       u16     major_fw_version;
+       u8      minor_fw_version;
+       u8      sub_fw_version;
+       u8      fw_build_num;
+       u8      load_from_file;
+};
+
+struct qlc_83xx_reset {
+       struct qlc_83xx_reset_hdr *hdr;
+       int     seq_index;
+       int     seq_error;
+       int     array_index;
+       u32     array[QLC_83XX_MAX_RESET_SEQ_ENTRIES];
+       u8      *buff;
+       u8      *stop_offset;
+       u8      *start_offset;
+       u8      *init_offset;
+       u8      seq_end;
+       u8      template_end;
+};
+
+#define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY         0x1
+#define QLC_83XX_IDC_GRACEFULL_RESET                   0x2
+#define QLC_83XX_IDC_TIMESTAMP                         0
+#define QLC_83XX_IDC_DURATION                          1
+#define QLC_83XX_IDC_INIT_TIMEOUT_SECS                 30
+#define QLC_83XX_IDC_RESET_ACK_TIMEOUT_SECS            10
+#define QLC_83XX_IDC_RESET_TIMEOUT_SECS                10
+#define QLC_83XX_IDC_QUIESCE_ACK_TIMEOUT_SECS          20
+#define QLC_83XX_IDC_FW_POLL_DELAY                     (1 * HZ)
+#define QLC_83XX_IDC_FW_FAIL_THRESH                    2
+#define QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO       8
+#define QLC_83XX_IDC_MAX_CNA_FUNCTIONS                 16
+#define QLC_83XX_IDC_MAJOR_VERSION                     1
+#define QLC_83XX_IDC_MINOR_VERSION                     0
+#define QLC_83XX_IDC_FLASH_PARAM_ADDR                  0x3e8020
+
+/* Mailbox process AEN count */
+#define QLC_83XX_MBX_AEN_CNT 5
+
+struct qlcnic_adapter;
+struct qlc_83xx_idc {
+       int (*state_entry) (struct qlcnic_adapter *);
+       u64             sec_counter;
+       u64             delay;
+       unsigned long   status;
+       int             err_code;
+       int             collect_dump;
+       u8              curr_state;
+       u8              prev_state;
+       u8              vnic_state;
+       u8              vnic_wait_limit;
+       u8              quiesce_req;
+       char            **name;
+};
+
+/* Mailbox process AEN count */
+#define QLC_83XX_IDC_COMP_AEN                  3
+#define QLC_83XX_MBX_AEN_CNT                   5
+#define QLC_83XX_MODULE_LOADED                 1
+#define QLC_83XX_MBX_READY                     2
+#define QLC_83XX_MBX_AEN_ACK                   3
+#define QLC_83XX_SFP_PRESENT(data)             ((data) & 3)
+#define QLC_83XX_SFP_ERR(data)                 (((data) >> 2) & 3)
+#define QLC_83XX_SFP_MODULE_TYPE(data)         (((data) >> 4) & 0x1F)
+#define QLC_83XX_SFP_CU_LENGTH(data)           (LSB((data) >> 16))
+#define QLC_83XX_SFP_TX_FAULT(data)            ((data) & BIT_10)
+#define QLC_83XX_SFP_10G_CAPABLE(data)         ((data) & BIT_11)
+#define QLC_83XX_LINK_STATS(data)              ((data) & BIT_0)
+#define QLC_83XX_CURRENT_LINK_SPEED(data)      (((data) >> 3) & 7)
+#define QLC_83XX_LINK_PAUSE(data)              (((data) >> 6) & 3)
+#define QLC_83XX_LINK_LB(data)                 (((data) >> 8) & 7)
+#define QLC_83XX_LINK_FEC(data)                ((data) & BIT_12)
+#define QLC_83XX_LINK_EEE(data)                ((data) & BIT_13)
+#define QLC_83XX_DCBX(data)                    (((data) >> 28) & 7)
+#define QLC_83XX_AUTONEG(data)                 ((data) & BIT_15)
+#define QLC_83XX_CFG_STD_PAUSE                 (1 << 5)
+#define QLC_83XX_CFG_STD_TX_PAUSE              (1 << 20)
+#define QLC_83XX_CFG_STD_RX_PAUSE              (2 << 20)
+#define QLC_83XX_CFG_STD_TX_RX_PAUSE           (3 << 20)
+#define QLC_83XX_ENABLE_AUTONEG                (1 << 15)
+#define QLC_83XX_CFG_LOOPBACK_HSS              (2 << 1)
+#define QLC_83XX_CFG_LOOPBACK_PHY              (3 << 1)
+#define QLC_83XX_CFG_LOOPBACK_EXT              (4 << 1)
+
+/* LED configuration settings */
+#define QLC_83XX_ENABLE_BEACON         0xe
+#define QLC_83XX_LED_RATE              0xff
+#define QLC_83XX_LED_ACT               (1 << 10)
+#define QLC_83XX_LED_MOD               (0 << 13)
+#define QLC_83XX_LED_CONFIG    (QLC_83XX_LED_RATE | QLC_83XX_LED_ACT | \
+                                QLC_83XX_LED_MOD)
+
+#define QLC_83XX_10M_LINK      1
+#define QLC_83XX_100M_LINK     2
+#define QLC_83XX_1G_LINK       3
+#define QLC_83XX_10G_LINK      4
+#define QLC_83XX_STAT_TX       3
+#define QLC_83XX_STAT_RX       2
+#define QLC_83XX_STAT_MAC      1
+#define QLC_83XX_TX_STAT_REGS  14
+#define QLC_83XX_RX_STAT_REGS  40
+#define QLC_83XX_MAC_STAT_REGS 80
+
+#define QLC_83XX_GET_FUNC_PRIVILEGE(VAL, FN)   (0x3 & ((VAL) >> (FN * 2)))
+#define QLC_83XX_SET_FUNC_OPMODE(VAL, FN)      ((VAL) << (FN * 2))
+#define QLC_83XX_DEFAULT_OPMODE                        0x55555555
+#define QLC_83XX_PRIVLEGED_FUNC                        0x1
+#define QLC_83XX_VIRTUAL_FUNC                          0x2
+
+#define QLC_83XX_LB_MAX_FILTERS                        2048
+#define QLC_83XX_LB_BUCKET_SIZE                        256
+#define QLC_83XX_MINIMUM_VECTOR                        3
+
+#define QLC_83XX_GET_FUNC_MODE_FROM_NPAR_INFO(val)     (val & 0x80000000)
+#define QLC_83XX_GET_LRO_CAPABILITY(val)               (val & 0x20)
+#define QLC_83XX_GET_LSO_CAPABILITY(val)               (val & 0x40)
+#define QLC_83XX_GET_LSO_CAPABILITY(val)               (val & 0x40)
+#define QLC_83XX_GET_HW_LRO_CAPABILITY(val)            (val & 0x400)
+#define QLC_83XX_GET_VLAN_ALIGN_CAPABILITY(val)        (val & 0x4000)
+#define QLC_83XX_VIRTUAL_NIC_MODE                      0xFF
+#define QLC_83XX_DEFAULT_MODE                          0x0
+#define QLCNIC_BRDTYPE_83XX_10G                        0x0083
+
+#define QLC_83XX_FLASH_SPI_STATUS              0x2808E010
+#define QLC_83XX_FLASH_SPI_CONTROL             0x2808E014
+#define QLC_83XX_FLASH_STATUS                  0x42100004
+#define QLC_83XX_FLASH_CONTROL                 0x42110004
+#define QLC_83XX_FLASH_ADDR                    0x42110008
+#define QLC_83XX_FLASH_WRDATA                  0x4211000C
+#define QLC_83XX_FLASH_RDDATA                  0x42110018
+#define QLC_83XX_FLASH_DIRECT_WINDOW           0x42110030
+#define QLC_83XX_FLASH_DIRECT_DATA(DATA)       (0x42150000 | (0x0000FFFF&DATA))
+#define QLC_83XX_FLASH_SECTOR_ERASE_CMD        0xdeadbeef
+#define QLC_83XX_FLASH_WRITE_CMD               0xdacdacda
+#define QLC_83XX_FLASH_BULK_WRITE_CMD          0xcadcadca
+#define QLC_83XX_FLASH_READ_RETRY_COUNT        5000
+#define QLC_83XX_FLASH_STATUS_READY            0x6
+#define QLC_83XX_FLASH_BULK_WRITE_MIN          2
+#define QLC_83XX_FLASH_BULK_WRITE_MAX          64
+#define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY   1
+#define QLC_83XX_ERASE_MODE                    1
+#define QLC_83XX_WRITE_MODE                    2
+#define QLC_83XX_BULK_WRITE_MODE               3
+#define QLC_83XX_FLASH_FDT_WRITE_DEF_SIG       0xFD0100
+#define QLC_83XX_FLASH_FDT_ERASE_DEF_SIG       0xFD0300
+#define QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL     0xFD009F
+#define QLC_83XX_FLASH_OEM_ERASE_SIG           0xFD03D8
+#define QLC_83XX_FLASH_OEM_WRITE_SIG           0xFD0101
+#define QLC_83XX_FLASH_OEM_READ_SIG            0xFD0005
+#define QLC_83XX_FLASH_ADDR_TEMP_VAL           0x00800000
+#define QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL    0x00800001
+#define QLC_83XX_FLASH_WRDATA_DEF              0x0
+#define QLC_83XX_FLASH_READ_CTRL               0x3F
+#define QLC_83XX_FLASH_SPI_CTRL                0x4
+#define QLC_83XX_FLASH_FIRST_ERASE_MS_VAL      0x2
+#define QLC_83XX_FLASH_SECOND_ERASE_MS_VAL     0x5
+#define QLC_83XX_FLASH_LAST_ERASE_MS_VAL       0x3D
+#define QLC_83XX_FLASH_FIRST_MS_PATTERN        0x43
+#define QLC_83XX_FLASH_SECOND_MS_PATTERN       0x7F
+#define QLC_83XX_FLASH_LAST_MS_PATTERN         0x7D
+#define QLC_83xx_FLASH_MAX_WAIT_USEC           100
+#define QLC_83XX_FLASH_LOCK_TIMEOUT            10000
+
+/* Additional registers in 83xx */
+enum qlc_83xx_ext_regs {
+       QLCNIC_GLOBAL_RESET = 0,
+       QLCNIC_WILDCARD,
+       QLCNIC_INFORMANT,
+       QLCNIC_HOST_MBX_CTRL,
+       QLCNIC_FW_MBX_CTRL,
+       QLCNIC_BOOTLOADER_ADDR,
+       QLCNIC_BOOTLOADER_SIZE,
+       QLCNIC_FW_IMAGE_ADDR,
+       QLCNIC_MBX_INTR_ENBL,
+       QLCNIC_DEF_INT_MASK,
+       QLCNIC_DEF_INT_ID,
+       QLC_83XX_IDC_MAJ_VERSION,
+       QLC_83XX_IDC_DEV_STATE,
+       QLC_83XX_IDC_DRV_PRESENCE,
+       QLC_83XX_IDC_DRV_ACK,
+       QLC_83XX_IDC_CTRL,
+       QLC_83XX_IDC_DRV_AUDIT,
+       QLC_83XX_IDC_MIN_VERSION,
+       QLC_83XX_RECOVER_DRV_LOCK,
+       QLC_83XX_IDC_PF_0,
+       QLC_83XX_IDC_PF_1,
+       QLC_83XX_IDC_PF_2,
+       QLC_83XX_IDC_PF_3,
+       QLC_83XX_IDC_PF_4,
+       QLC_83XX_IDC_PF_5,
+       QLC_83XX_IDC_PF_6,
+       QLC_83XX_IDC_PF_7,
+       QLC_83XX_IDC_PF_8,
+       QLC_83XX_IDC_PF_9,
+       QLC_83XX_IDC_PF_10,
+       QLC_83XX_IDC_PF_11,
+       QLC_83XX_IDC_PF_12,
+       QLC_83XX_IDC_PF_13,
+       QLC_83XX_IDC_PF_14,
+       QLC_83XX_IDC_PF_15,
+       QLC_83XX_IDC_DEV_PARTITION_INFO_1,
+       QLC_83XX_IDC_DEV_PARTITION_INFO_2,
+       QLC_83XX_DRV_OP_MODE,
+       QLC_83XX_VNIC_STATE,
+       QLC_83XX_DRV_LOCK,
+       QLC_83XX_DRV_UNLOCK,
+       QLC_83XX_DRV_LOCK_ID,
+       QLC_83XX_ASIC_TEMP,
+};
+
+/* 83xx funcitons */
+int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
+int qlcnic_83xx_mbx_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *);
+int qlcnic_send_ctrl_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *, u32);
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong);
+int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []);
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *);
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, __le16);
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int);
+
+int qlcnic_83xx_napi_add(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_83xx_napi_del(struct qlcnic_adapter *);
+void qlcnic_83xx_napi_enable(struct qlcnic_adapter *);
+void qlcnic_83xx_napi_disable(struct qlcnic_adapter *);
+int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32);
+int qlcnic_ind_rd(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *,
+                             struct qlcnic_host_tx_ring *, int);
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int);
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool);
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *);
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8,
+                              struct qlcnic_cmd_args *);
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *,
+                              struct qlcnic_adapter *, u32);
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *);
+void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *,
+                         struct qlcnic_info *);
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_handle_aen(int, void *);
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_tmp_intr(int, void *);
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *,
+                            struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_check_vf(struct qlcnic_adapter *,
+                         const struct pci_device_id *);
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *);
+int qlcnic_83xx_get_port_config(struct qlcnic_adapter *);
+int qlcnic_83xx_set_port_config(struct qlcnic_adapter *);
+int qlcnic_enable_eswitch(struct qlcnic_adapter *, u8, u8);
+int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *);
+int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *);
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *);
+void qlcnic_83xx_register_map(struct qlcnic_hardware_context *);
+void qlcnic_83xx_idc_aen_work(struct work_struct *);
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *, __be32, int);
+
+int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *, u32, u32 *, int);
+int qlcnic_83xx_flash_write32(struct qlcnic_adapter *, u32, u32 *);
+int qlcnic_83xx_lock_flash(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *);
+int qlcnic_83xx_save_flash_status(struct qlcnic_adapter *);
+int qlcnic_83xx_restore_flash_status(struct qlcnic_adapter *, int);
+int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *);
+int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *);
+int qlcnic_83xx_flash_read32(struct qlcnic_adapter *, u32, u8 *, int);
+int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *,
+                                     u32, u8 *, int);
+int qlcnic_83xx_init(struct qlcnic_adapter *);
+int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *);
+int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);
+void qlcnic_83xx_idc_poll_dev_state(struct work_struct *);
+int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *);
+void qlcnic_83xx_idc_exit(struct qlcnic_adapter *);
+void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_lock_driver(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *);
+int qlcnic_83xx_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *, u64, u32 *, u32);
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *);
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *,
+                                   struct qlcnic_info *, u8);
+int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *);
+
+void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *);
+void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data);
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *,
+                               struct ethtool_pauseparam *);
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *,
+                              struct ethtool_pauseparam *);
+int qlcnic_83xx_test_link(struct qlcnic_adapter *);
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *);
+int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *);
+int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *);
+int qlcnic_83xx_interrupt_test(struct qlcnic_adapter *,
+                              struct qlcnic_cmd_args *);
+int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
+#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
new file mode 100644 (file)
index 0000000..c9e24a8
--- /dev/null
@@ -0,0 +1,2050 @@
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+/* Reset template definitions */
+#define QLC_83XX_RESTART_TEMPLATE_SIZE         0x2000
+#define QLC_83XX_RESET_TEMPLATE_ADDR           0x4F0000
+#define QLC_83XX_RESET_SEQ_VERSION             0x0101
+
+#define QLC_83XX_OPCODE_NOP                    0x0000
+#define QLC_83XX_OPCODE_WRITE_LIST             0x0001
+#define QLC_83XX_OPCODE_READ_WRITE_LIST                0x0002
+#define QLC_83XX_OPCODE_POLL_LIST              0x0004
+#define QLC_83XX_OPCODE_POLL_WRITE_LIST                0x0008
+#define QLC_83XX_OPCODE_READ_MODIFY_WRITE      0x0010
+#define QLC_83XX_OPCODE_SEQ_PAUSE              0x0020
+#define QLC_83XX_OPCODE_SEQ_END                        0x0040
+#define QLC_83XX_OPCODE_TMPL_END               0x0080
+#define QLC_83XX_OPCODE_POLL_READ_LIST         0x0100
+
+static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
+static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
+static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
+static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter);
+
+/* Template header */
+struct qlc_83xx_reset_hdr {
+       u16     version;
+       u16     signature;
+       u16     size;
+       u16     entries;
+       u16     hdr_size;
+       u16     checksum;
+       u16     init_offset;
+       u16     start_offset;
+} __packed;
+
+/* Command entry header. */
+struct qlc_83xx_entry_hdr {
+       u16 cmd;
+       u16 size;
+       u16 count;
+       u16 delay;
+} __packed;
+
+/* Generic poll command */
+struct qlc_83xx_poll {
+       u32     mask;
+       u32     status;
+} __packed;
+
+/* Read modify write command */
+struct qlc_83xx_rmw {
+       u32     mask;
+       u32     xor_value;
+       u32     or_value;
+       u8      shl;
+       u8      shr;
+       u8      index_a;
+       u8      rsvd;
+} __packed;
+
+/* Generic command with 2 DWORD */
+struct qlc_83xx_entry {
+       u32 arg1;
+       u32 arg2;
+} __packed;
+
+/* Generic command with 4 DWORD */
+struct qlc_83xx_quad_entry {
+       u32 dr_addr;
+       u32 dr_value;
+       u32 ar_addr;
+       u32 ar_value;
+} __packed;
+static const char *const qlc_83xx_idc_states[] = {
+       "Unknown",
+       "Cold",
+       "Init",
+       "Ready",
+       "Need Reset",
+       "Need Quiesce",
+       "Failed",
+       "Quiesce"
+};
+
+/* Device States */
+enum qlcnic_83xx_states {
+       QLC_83XX_IDC_DEV_UNKNOWN,
+       QLC_83XX_IDC_DEV_COLD,
+       QLC_83XX_IDC_DEV_INIT,
+       QLC_83XX_IDC_DEV_READY,
+       QLC_83XX_IDC_DEV_NEED_RESET,
+       QLC_83XX_IDC_DEV_NEED_QUISCENT,
+       QLC_83XX_IDC_DEV_FAILED,
+       QLC_83XX_IDC_DEV_QUISCENT
+};
+
+static int
+qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+       if ((val & 0xFFFF))
+               return 1;
+       else
+               return 0;
+}
+
+static void qlcnic_83xx_idc_log_state_history(struct qlcnic_adapter *adapter)
+{
+       u32 cur, prev;
+       cur = adapter->ahw->idc.curr_state;
+       prev = adapter->ahw->idc.prev_state;
+
+       dev_info(&adapter->pdev->dev,
+                "current state  = %s,  prev state = %s\n",
+                adapter->ahw->idc.name[cur],
+                adapter->ahw->idc.name[prev]);
+}
+
+static int qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter *adapter,
+                                           u8 mode, int lock)
+{
+       u32 val;
+       int seconds;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = adapter->portnum & 0xf;
+       val |= mode << 7;
+       if (mode)
+               seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
+       else
+               seconds = jiffies / HZ;
+
+       val |= seconds << 8;
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT, val);
+       adapter->ahw->idc.sec_counter = jiffies / HZ;
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static void qlcnic_83xx_idc_update_minor_version(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION);
+       val = val & ~(0x3 << (adapter->portnum * 2));
+       val = val | (QLC_83XX_IDC_MINOR_VERSION << (adapter->portnum * 2));
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION, val);
+}
+
+static int qlcnic_83xx_idc_update_major_version(struct qlcnic_adapter *adapter,
+                                               int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+       val = val & ~0xFF;
+       val = val | QLC_83XX_IDC_MAJOR_VERSION;
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION, val);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_idc_update_drv_presence_reg(struct qlcnic_adapter *adapter,
+                                       int status, int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+
+       if (status)
+               val = val | (1 << adapter->portnum);
+       else
+               val = val & ~(1 << adapter->portnum);
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+       qlcnic_83xx_idc_update_minor_version(adapter);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_check_major_version(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       u8 version;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+       version = val & 0xFF;
+
+       if (version != QLC_83XX_IDC_MAJOR_VERSION) {
+               dev_info(&adapter->pdev->dev,
+                        "%s:mismatch. version 0x%x, expected version 0x%x\n",
+                        __func__, version, QLC_83XX_IDC_MAJOR_VERSION);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_clear_registers(struct qlcnic_adapter *adapter,
+                                          int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, 0);
+       /* Clear gracefull reset bit */
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+       val &= ~QLC_83XX_IDC_GRACEFULL_RESET;
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_update_drv_ack_reg(struct qlcnic_adapter *adapter,
+                                             int flag, int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+       if (flag)
+               val = val | (1 << adapter->portnum);
+       else
+               val = val & ~(1 << adapter->portnum);
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, val);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_check_timeout(struct qlcnic_adapter *adapter,
+                                        int time_limit)
+{
+       u64 seconds;
+
+       seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
+       if (seconds <= time_limit)
+               return 0;
+       else
+               return -EBUSY;
+}
+
+/**
+ * qlcnic_83xx_idc_check_reset_ack_reg
+ *
+ * @adapter: adapter structure
+ *
+ * Check ACK wait limit and clear the functions which failed to ACK
+ *
+ * Return 0 if all functions have acknowledged the reset request.
+ **/
+static int qlcnic_83xx_idc_check_reset_ack_reg(struct qlcnic_adapter *adapter)
+{
+       int timeout;
+       u32 ack, presence, val;
+
+       timeout = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
+       ack = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+       presence = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+       dev_info(&adapter->pdev->dev,
+                "%s: ack = 0x%x, presence = 0x%x\n", __func__, ack, presence);
+       if (!((ack & presence) == presence)) {
+               if (qlcnic_83xx_idc_check_timeout(adapter, timeout)) {
+                       /* Clear functions which failed to ACK */
+                       dev_info(&adapter->pdev->dev,
+                                "%s: ACK wait exceeds time limit\n", __func__);
+                       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+                       val = val & ~(ack ^ presence);
+                       if (qlcnic_83xx_lock_driver(adapter))
+                               return -EBUSY;
+                       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+                       dev_info(&adapter->pdev->dev,
+                                "%s: updated drv presence reg = 0x%x\n",
+                                __func__, val);
+                       qlcnic_83xx_unlock_driver(adapter);
+                       return 0;
+
+               } else {
+                       return 1;
+               }
+       } else {
+               dev_info(&adapter->pdev->dev,
+                        "%s: Reset ACK received from all functions\n",
+                        __func__);
+               return 0;
+       }
+}
+
+/**
+ * qlcnic_83xx_idc_tx_soft_reset
+ *
+ * @adapter: adapter structure
+ *
+ * Handle context deletion and recreation request from transmit routine
+ *
+ * Returns -EBUSY  or Success (0)
+ *
+ **/
+static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EBUSY;
+
+       netif_device_detach(netdev);
+       qlcnic_down(adapter, netdev);
+       qlcnic_up(adapter, netdev);
+       netif_device_attach(netdev);
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       dev_err(&adapter->pdev->dev, "%s:\n", __func__);
+
+       adapter->netdev->trans_start = jiffies;
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_detach_driver
+ *
+ * @adapter: adapter structure
+ * Detach net interface, stop TX and cleanup resources before the HW reset.
+ * Returns: None
+ *
+ **/
+static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter)
+{
+       int i;
+       struct net_device *netdev = adapter->netdev;
+
+       netif_device_detach(netdev);
+       /* Disable mailbox interrupt */
+       QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0);
+       qlcnic_down(adapter, netdev);
+       for (i = 0; i < adapter->ahw->num_msix; i++) {
+               adapter->ahw->intr_tbl[i].id = i;
+               adapter->ahw->intr_tbl[i].enabled = 0;
+               adapter->ahw->intr_tbl[i].src = 0;
+       }
+}
+
+/**
+ * qlcnic_83xx_idc_attach_driver
+ *
+ * @adapter: adapter structure
+ *
+ * Re-attach and re-enable net interface
+ * Returns: None
+ *
+ **/
+static void qlcnic_83xx_idc_attach_driver(struct qlcnic_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       if (netif_running(netdev)) {
+               if (qlcnic_up(adapter, netdev))
+                       goto done;
+               qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+       }
+done:
+       netif_device_attach(netdev);
+       if (netif_running(netdev)) {
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
+       }
+}
+
+static int qlcnic_83xx_idc_enter_failed_state(struct qlcnic_adapter *adapter,
+                                             int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       qlcnic_83xx_idc_clear_registers(adapter, 0);
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_FAILED);
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       qlcnic_83xx_idc_log_state_history(adapter);
+       dev_info(&adapter->pdev->dev, "Device will enter failed state\n");
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_enter_init_state(struct qlcnic_adapter *adapter,
+                                           int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_INIT);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_enter_need_quiesce(struct qlcnic_adapter *adapter,
+                                             int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+              QLC_83XX_IDC_DEV_NEED_QUISCENT);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_idc_enter_need_reset_state(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+              QLC_83XX_IDC_DEV_NEED_RESET);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_enter_ready_state(struct qlcnic_adapter *adapter,
+                                            int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_READY);
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_find_reset_owner_id
+ *
+ * @adapter: adapter structure
+ *
+ * NIC gets precedence over ISCSI and ISCSI has precedence over FCOE.
+ * Within the same class, function with lowest PCI ID assumes ownership
+ *
+ * Returns: reset owner id or failure indication (-EIO)
+ *
+ **/
+static int qlcnic_83xx_idc_find_reset_owner_id(struct qlcnic_adapter *adapter)
+{
+       u32 reg, reg1, reg2, i, j, owner, class;
+
+       reg1 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_1);
+       reg2 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_2);
+       owner = QLCNIC_TYPE_NIC;
+       i = 0;
+       j = 0;
+       reg = reg1;
+
+       do {
+               class = (((reg & (0xF << j * 4)) >> j * 4) & 0x3);
+               if (class == owner)
+                       break;
+               if (i == (QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO - 1)) {
+                       reg = reg2;
+                       j = 0;
+               } else {
+                       j++;
+               }
+
+               if (i == (QLC_83XX_IDC_MAX_CNA_FUNCTIONS - 1)) {
+                       if (owner == QLCNIC_TYPE_NIC)
+                               owner = QLCNIC_TYPE_ISCSI;
+                       else if (owner == QLCNIC_TYPE_ISCSI)
+                               owner = QLCNIC_TYPE_FCOE;
+                       else if (owner == QLCNIC_TYPE_FCOE)
+                               return -EIO;
+                       reg = reg1;
+                       j = 0;
+                       i = 0;
+               }
+       } while (i++ < QLC_83XX_IDC_MAX_CNA_FUNCTIONS);
+
+       return i;
+}
+
+static int qlcnic_83xx_idc_restart_hw(struct qlcnic_adapter *adapter, int lock)
+{
+       int ret = 0;
+
+       ret = qlcnic_83xx_restart_hw(adapter);
+
+       if (ret) {
+               qlcnic_83xx_idc_enter_failed_state(adapter, lock);
+       } else {
+               qlcnic_83xx_idc_clear_registers(adapter, lock);
+               ret = qlcnic_83xx_idc_enter_ready_state(adapter, lock);
+       }
+
+       return ret;
+}
+
+static int qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter)
+{
+       u32 status;
+
+       status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+
+       if (status & QLCNIC_RCODE_FATAL_ERROR) {
+               dev_err(&adapter->pdev->dev,
+                       "peg halt status1=0x%x\n", status);
+               if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) {
+                       dev_err(&adapter->pdev->dev,
+                               "On board active cooling fan failed. "
+                               "Device has been halted.\n");
+                       dev_err(&adapter->pdev->dev,
+                               "Replace the adapter.\n");
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
+{
+       qlcnic_83xx_enable_mbx_intrpt(adapter);
+       if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               if (qlcnic_83xx_config_intrpt(adapter, 1)) {
+                       netdev_err(adapter->netdev,
+                                  "Failed to enable mbx intr\n");
+                       return -EIO;
+               }
+       }
+
+       if (qlcnic_83xx_configure_opmode(adapter)) {
+               qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+               return -EIO;
+       }
+
+       if (adapter->nic_ops->init_driver(adapter)) {
+               qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+               return -EIO;
+       }
+
+       qlcnic_83xx_idc_attach_driver(adapter);
+
+       return 0;
+}
+
+static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
+{
+       qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1);
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+       qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+       set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+       adapter->ahw->idc.quiesce_req = 0;
+       adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+       adapter->ahw->idc.err_code = 0;
+       adapter->ahw->idc.collect_dump = 0;
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state_entry
+ *
+ * @adapter: adapter structure
+ *
+ * Perform ready state initialization, this routine will get invoked only
+ * once from READY state.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY) {
+               qlcnic_83xx_idc_update_idc_params(adapter);
+               /* Re-attach the device if required */
+               if ((ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) ||
+                   (ahw->idc.prev_state == QLC_83XX_IDC_DEV_INIT)) {
+                       if (qlcnic_83xx_idc_reattach_driver(adapter))
+                               return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_vnic_pf_entry
+ *
+ * @adapter: adapter structure
+ *
+ * Ensure vNIC mode privileged function starts only after vNIC mode is
+ * enabled by management function.
+ * If vNIC mode is ready, start initialization.
+ *
+ * Returns: -EIO or 0
+ *
+ **/
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *adapter)
+{
+       u32 state;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Privileged function waits till mgmt function enables VNIC mode */
+       state = QLCRDX(adapter->ahw, QLC_83XX_VNIC_STATE);
+       if (state != QLCNIC_DEV_NPAR_OPER) {
+               if (!ahw->idc.vnic_wait_limit--) {
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+                       return -EIO;
+               }
+               dev_info(&adapter->pdev->dev, "vNIC mode disabled\n");
+               return -EIO;
+
+       } else {
+               /* Perform one time initialization from ready state */
+               if (ahw->idc.vnic_state != QLCNIC_DEV_NPAR_OPER) {
+                       qlcnic_83xx_idc_update_idc_params(adapter);
+
+                       /* If the previous state is UNKNOWN, device will be
+                          already attached properly by Init routine*/
+                       if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_UNKNOWN) {
+                               if (qlcnic_83xx_idc_reattach_driver(adapter))
+                                       return -EIO;
+                       }
+                       adapter->ahw->idc.vnic_state =  QLCNIC_DEV_NPAR_OPER;
+                       dev_info(&adapter->pdev->dev, "vNIC mode enabled\n");
+               }
+       }
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->idc.err_code = -EIO;
+       dev_err(&adapter->pdev->dev,
+               "%s: Device in unknown state\n", __func__);
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_cold_state
+ *
+ * @adapter: adapter structure
+ *
+ * If HW is up and running device will enter READY state.
+ * If firmware image from host needs to be loaded, device is
+ * forced to start with the file firmware image.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_cold_state_handler(struct qlcnic_adapter *adapter)
+{
+       qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 0);
+       qlcnic_83xx_idc_update_audit_reg(adapter, 1, 0);
+
+       if (qlcnic_load_fw_file) {
+               qlcnic_83xx_idc_restart_hw(adapter, 0);
+       } else {
+               if (qlcnic_83xx_check_hw_status(adapter)) {
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 0);
+                       return -EIO;
+               } else {
+                       qlcnic_83xx_idc_enter_ready_state(adapter, 0);
+               }
+       }
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_init_state
+ *
+ * @adapter: adapter structure
+ *
+ * Reset owner will restart the device from this state.
+ * Device will enter failed state if it remains
+ * in this state for more than DEV_INIT time limit.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter)
+{
+       int timeout, ret = 0;
+       u32 owner;
+
+       timeout = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
+       if (adapter->ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) {
+               owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
+               if (adapter->ahw->pci_func == owner)
+                       ret = qlcnic_83xx_idc_restart_hw(adapter, 1);
+       } else {
+               ret = qlcnic_83xx_idc_check_timeout(adapter, timeout);
+               return ret;
+       }
+
+       return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state
+ *
+ * @adapter: adapter structure
+ *
+ * Perform IDC protocol specicifed actions after monitoring device state and
+ * events.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int ret = 0;
+
+       /* Perform NIC configuration based ready state entry actions */
+       if (ahw->idc.state_entry(adapter))
+               return -EIO;
+
+       if (qlcnic_check_temp(adapter)) {
+               if (ahw->temp == QLCNIC_TEMP_PANIC) {
+                       qlcnic_83xx_idc_check_fan_failure(adapter);
+                       dev_err(&adapter->pdev->dev,
+                               "Error: device temperature %d above limits\n",
+                               adapter->ahw->temp);
+                       clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+                       set_bit(__QLCNIC_RESETTING, &adapter->state);
+                       qlcnic_83xx_idc_detach_driver(adapter);
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+                       return -EIO;
+               }
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+       ret = qlcnic_83xx_check_heartbeat(adapter);
+       if (ret) {
+               adapter->flags |= QLCNIC_FW_HANG;
+               if (!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+                       clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+                       set_bit(__QLCNIC_RESETTING, &adapter->state);
+                       qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+               }
+               return -EIO;
+       }
+
+       if ((val & QLC_83XX_IDC_GRACEFULL_RESET) || ahw->idc.collect_dump) {
+               /* Move to need reset state and prepare for reset */
+               qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+               return ret;
+       }
+
+       /* Check for soft reset request */
+       if (ahw->reset_context &&
+           !(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+               qlcnic_83xx_idc_tx_soft_reset(adapter);
+               return ret;
+       }
+
+       /* Move to need quiesce state if requested */
+       if (adapter->ahw->idc.quiesce_req) {
+               qlcnic_83xx_idc_enter_need_quiesce(adapter, 1);
+               qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+               return ret;
+       }
+
+       return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_need_reset_state
+ *
+ * @adapter: adapter structure
+ *
+ * Device will remain in this state until:
+ *     Reset request ACK's are recieved from all the functions
+ *     Wait time exceeds max time limit
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
+{
+       int ret = 0;
+
+       if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
+               qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+               qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+               set_bit(__QLCNIC_RESETTING, &adapter->state);
+               clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+               if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
+                       qlcnic_83xx_disable_vnic_mode(adapter, 1);
+               qlcnic_83xx_idc_detach_driver(adapter);
+       }
+
+       /* Check ACK from other functions */
+       ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
+       if (ret) {
+               dev_info(&adapter->pdev->dev,
+                        "%s: Waiting for reset ACK\n", __func__);
+               return 0;
+       }
+
+       /* Transit to INIT state and restart the HW */
+       qlcnic_83xx_idc_enter_init_state(adapter, 1);
+
+       return ret;
+}
+
+static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter)
+{
+       dev_err(&adapter->pdev->dev, "%s: TBD\n", __func__);
+       return 0;
+}
+
+static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)
+{
+       dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__);
+       adapter->ahw->idc.err_code = -EIO;
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter)
+{
+       dev_info(&adapter->pdev->dev, "%s: TBD\n", __func__);
+       return 0;
+}
+
+static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,
+                                               u32 state)
+{
+       u32 cur, prev, next;
+
+       cur = adapter->ahw->idc.curr_state;
+       prev = adapter->ahw->idc.prev_state;
+       next = state;
+
+       if ((next < QLC_83XX_IDC_DEV_COLD) ||
+           (next > QLC_83XX_IDC_DEV_QUISCENT)) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: curr %d, prev %d, next state %d is  invalid\n",
+                       __func__, cur, prev, state);
+               return 1;
+       }
+
+       if ((cur == QLC_83XX_IDC_DEV_UNKNOWN) &&
+           (prev == QLC_83XX_IDC_DEV_UNKNOWN)) {
+               if ((next != QLC_83XX_IDC_DEV_COLD) &&
+                   (next != QLC_83XX_IDC_DEV_READY)) {
+                       dev_err(&adapter->pdev->dev,
+                               "%s: failed, cur %d prev %d next %d\n",
+                               __func__, cur, prev, next);
+                       return 1;
+               }
+       }
+
+       if (next == QLC_83XX_IDC_DEV_INIT) {
+               if ((prev != QLC_83XX_IDC_DEV_INIT) &&
+                   (prev != QLC_83XX_IDC_DEV_COLD) &&
+                   (prev != QLC_83XX_IDC_DEV_NEED_RESET)) {
+                       dev_err(&adapter->pdev->dev,
+                               "%s: failed, cur %d prev %d next %d\n",
+                               __func__, cur, prev, next);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
+{
+       if (adapter->fhash.fnum)
+               qlcnic_prune_lb_filters(adapter);
+}
+
+/**
+ * qlcnic_83xx_idc_poll_dev_state
+ *
+ * @work: kernel work queue structure used to schedule the function
+ *
+ * Poll device state periodically and perform state specific
+ * actions defined by Inter Driver Communication (IDC) protocol.
+ *
+ * Returns: None
+ *
+ **/
+void qlcnic_83xx_idc_poll_dev_state(struct work_struct *work)
+{
+       struct qlcnic_adapter *adapter;
+       u32 state;
+
+       adapter = container_of(work, struct qlcnic_adapter, fw_work.work);
+       state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+
+       if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
+               qlcnic_83xx_idc_log_state_history(adapter);
+               adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+       } else {
+               adapter->ahw->idc.curr_state = state;
+       }
+
+       switch (adapter->ahw->idc.curr_state) {
+       case QLC_83XX_IDC_DEV_READY:
+               qlcnic_83xx_idc_ready_state(adapter);
+               break;
+       case QLC_83XX_IDC_DEV_NEED_RESET:
+               qlcnic_83xx_idc_need_reset_state(adapter);
+               break;
+       case QLC_83XX_IDC_DEV_NEED_QUISCENT:
+               qlcnic_83xx_idc_need_quiesce_state(adapter);
+               break;
+       case QLC_83XX_IDC_DEV_FAILED:
+               qlcnic_83xx_idc_failed_state(adapter);
+               return;
+       case QLC_83XX_IDC_DEV_INIT:
+               qlcnic_83xx_idc_init_state(adapter);
+               break;
+       case QLC_83XX_IDC_DEV_QUISCENT:
+               qlcnic_83xx_idc_quiesce_state(adapter);
+               break;
+       default:
+               qlcnic_83xx_idc_unknown_state(adapter);
+               return;
+       }
+       adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state;
+       qlcnic_83xx_periodic_tasks(adapter);
+
+       /* Re-schedule the function */
+       if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status))
+               qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
+                                    adapter->ahw->idc.delay);
+}
+
+static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter)
+{
+       u32 idc_params, val;
+
+       if (qlcnic_83xx_lockless_flash_read32(adapter,
+                                             QLC_83XX_IDC_FLASH_PARAM_ADDR,
+                                             (u8 *)&idc_params, 1)) {
+               dev_info(&adapter->pdev->dev,
+                        "%s:failed to get IDC params from flash\n", __func__);
+               adapter->dev_init_timeo = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
+               adapter->reset_ack_timeo = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
+       } else {
+               adapter->dev_init_timeo = idc_params & 0xFFFF;
+               adapter->reset_ack_timeo = ((idc_params >> 16) & 0xFFFF);
+       }
+
+       adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+       adapter->ahw->idc.prev_state = QLC_83XX_IDC_DEV_UNKNOWN;
+       adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+       adapter->ahw->idc.err_code = 0;
+       adapter->ahw->idc.collect_dump = 0;
+       adapter->ahw->idc.name = (char **)qlc_83xx_idc_states;
+
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+       set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+
+       /* Check if reset recovery is disabled */
+       if (!qlcnic_auto_fw_reset) {
+               /* Propagate do not reset request to other functions */
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val = val | QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+       }
+}
+
+static int
+qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
+{
+       u32 state, val;
+
+       if (qlcnic_83xx_lock_driver(adapter))
+               return -EIO;
+
+       /* Clear driver lock register */
+       QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, 0);
+       if (qlcnic_83xx_idc_update_major_version(adapter, 0)) {
+               qlcnic_83xx_unlock_driver(adapter);
+               return -EIO;
+       }
+
+       state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+       if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
+               qlcnic_83xx_unlock_driver(adapter);
+               return -EIO;
+       }
+
+       if (state != QLC_83XX_IDC_DEV_COLD && qlcnic_load_fw_file) {
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+                      QLC_83XX_IDC_DEV_COLD);
+               state = QLC_83XX_IDC_DEV_COLD;
+       }
+
+       adapter->ahw->idc.curr_state = state;
+       /* First to load function should cold boot the device */
+       if (state == QLC_83XX_IDC_DEV_COLD)
+               qlcnic_83xx_idc_cold_state_handler(adapter);
+
+       /* Check if reset recovery is enabled */
+       if (qlcnic_auto_fw_reset) {
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val = val & ~QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+       }
+
+       qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
+{
+       int ret = -EIO;
+
+       qlcnic_83xx_setup_idc_parameters(adapter);
+
+       if (qlcnic_83xx_get_reset_instruction_template(adapter))
+               return ret;
+
+       if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) {
+               if (qlcnic_83xx_idc_first_to_load_function_handler(adapter))
+                       return -EIO;
+       } else {
+               if (qlcnic_83xx_idc_check_major_version(adapter))
+                       return -EIO;
+       }
+
+       qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+
+       return 0;
+}
+
+void qlcnic_83xx_idc_exit(struct qlcnic_adapter *adapter)
+{
+       int id;
+       u32 val;
+
+       while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               usleep_range(10000, 11000);
+
+       id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+       id = id & 0xFF;
+
+       if (id == adapter->portnum) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: wait for lock recovery.. %d\n", __func__, id);
+               msleep(20);
+               id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+               id = id & 0xFF;
+       }
+
+       /* Clear driver presence bit */
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+       val = val & ~(1 << adapter->portnum);
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+       clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+       cancel_delayed_work_sync(&adapter->fw_work);
+}
+
+void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key)
+{
+       u32 val;
+
+       if (qlcnic_83xx_lock_driver(adapter)) {
+               dev_err(&adapter->pdev->dev,
+                       "%s:failed, please retry\n", __func__);
+               return;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+       if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) ||
+           !qlcnic_auto_fw_reset) {
+               dev_err(&adapter->pdev->dev,
+                       "%s:failed, device in non reset mode\n", __func__);
+               qlcnic_83xx_unlock_driver(adapter);
+               return;
+       }
+
+       if (key == QLCNIC_FORCE_FW_RESET) {
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val = val | QLC_83XX_IDC_GRACEFULL_RESET;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+       } else if (key == QLCNIC_FORCE_FW_DUMP_KEY) {
+               adapter->ahw->idc.collect_dump = 1;
+       }
+
+       qlcnic_83xx_unlock_driver(adapter);
+       return;
+}
+
+static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter)
+{
+       u8 *p_cache;
+       u32 src, size;
+       u64 dest;
+       int ret = -EIO;
+
+       src = QLC_83XX_BOOTLOADER_FLASH_ADDR;
+       dest = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_ADDR);
+       size = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_SIZE);
+
+       /* alignment check */
+       if (size & 0xF)
+               size = (size + 16) & ~0xF;
+
+       p_cache = kzalloc(size, GFP_KERNEL);
+
+       if (p_cache == NULL) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to allocate memory for boot loader cache\n");
+               return -ENOMEM;
+       }
+       ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache,
+                                               size / sizeof(u32));
+       if (ret) {
+               kfree(p_cache);
+               return ret;
+       }
+       /* 16 byte write to MS memory */
+       ret = qlcnic_83xx_ms_mem_write128(adapter, dest, (u32 *)p_cache,
+                                         size / 16);
+       if (ret) {
+               kfree(p_cache);
+               return ret;
+       }
+       kfree(p_cache);
+
+       return ret;
+}
+
+static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
+{
+       u32 dest, *p_cache;
+       u64 addr;
+       u8 data[16];
+       size_t size;
+       int i, ret = -EIO;
+
+       dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
+       size = (adapter->ahw->fw_info.fw->size & ~0xF);
+       p_cache = (u32 *)adapter->ahw->fw_info.fw->data;
+       addr = (u64)dest;
+
+       ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
+                                         (u32 *)p_cache, size / 16);
+       if (ret) {
+               dev_err(&adapter->pdev->dev, "MS memory write failed\n");
+               release_firmware(adapter->ahw->fw_info.fw);
+               adapter->ahw->fw_info.fw = NULL;
+               return -EIO;
+       }
+
+       /* alignment check */
+       if (adapter->ahw->fw_info.fw->size & 0xF) {
+               addr = dest + size;
+               for (i = 0; i < (adapter->ahw->fw_info.fw->size & 0xF); i++)
+                       data[i] = adapter->ahw->fw_info.fw->data[size + i];
+               for (; i < 16; i++)
+                       data[i] = 0;
+               ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
+                                                 (u32 *)data, 1);
+               if (ret) {
+                       dev_err(&adapter->pdev->dev,
+                               "MS memory write failed\n");
+                       release_firmware(adapter->ahw->fw_info.fw);
+                       adapter->ahw->fw_info.fw = NULL;
+                       return -EIO;
+               }
+       }
+       release_firmware(adapter->ahw->fw_info.fw);
+       adapter->ahw->fw_info.fw = NULL;
+
+       return 0;
+}
+
+static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
+{
+       int i, j;
+       u32 val = 0, val1 = 0, reg = 0;
+
+       val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG);
+       dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val);
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       dev_info(&adapter->pdev->dev,
+                                "Port 0 RxB Pause Threshold Regs[TC7..TC0]:");
+                       reg = QLC_83XX_PORT0_THRESHOLD;
+               } else if (j == 1) {
+                       dev_info(&adapter->pdev->dev,
+                                "Port 1 RxB Pause Threshold Regs[TC7..TC0]:");
+                       reg = QLC_83XX_PORT1_THRESHOLD;
+               }
+               for (i = 0; i < 8; i++) {
+                       val = QLCRD32(adapter, reg + (i * 0x4));
+                       dev_info(&adapter->pdev->dev, "0x%x  ", val);
+               }
+               dev_info(&adapter->pdev->dev, "\n");
+       }
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       dev_info(&adapter->pdev->dev,
+                                "Port 0 RxB TC Max Cell Registers[4..1]:");
+                       reg = QLC_83XX_PORT0_TC_MC_REG;
+               } else if (j == 1) {
+                       dev_info(&adapter->pdev->dev,
+                                "Port 1 RxB TC Max Cell Registers[4..1]:");
+                       reg = QLC_83XX_PORT1_TC_MC_REG;
+               }
+               for (i = 0; i < 4; i++) {
+                       val = QLCRD32(adapter, reg + (i * 0x4));
+                        dev_info(&adapter->pdev->dev, "0x%x  ", val);
+               }
+               dev_info(&adapter->pdev->dev, "\n");
+       }
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       dev_info(&adapter->pdev->dev,
+                                "Port 0 RxB Rx TC Stats[TC7..TC0]:");
+                       reg = QLC_83XX_PORT0_TC_STATS;
+               } else if (j == 1) {
+                       dev_info(&adapter->pdev->dev,
+                                "Port 1 RxB Rx TC Stats[TC7..TC0]:");
+                       reg = QLC_83XX_PORT1_TC_STATS;
+               }
+               for (i = 7; i >= 0; i--) {
+                       val = QLCRD32(adapter, reg);
+                       val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
+                       QLCWR32(adapter, reg, (val | (i << 29)));
+                       val = QLCRD32(adapter, reg);
+                       dev_info(&adapter->pdev->dev, "0x%x  ", val);
+               }
+               dev_info(&adapter->pdev->dev, "\n");
+       }
+
+       val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD);
+       val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD);
+       dev_info(&adapter->pdev->dev,
+                "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
+                val, val1);
+}
+
+
+static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
+{
+       u32 reg = 0, i, j;
+
+       if (qlcnic_83xx_lock_driver(adapter)) {
+               dev_err(&adapter->pdev->dev,
+                       "%s:failed to acquire driver lock\n", __func__);
+               return;
+       }
+
+       qlcnic_83xx_dump_pause_control_regs(adapter);
+       QLCWR32(adapter, QLC_83XX_SRE_SHIM_REG, 0x0);
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0)
+                       reg = QLC_83XX_PORT0_THRESHOLD;
+               else if (j == 1)
+                       reg = QLC_83XX_PORT1_THRESHOLD;
+
+               for (i = 0; i < 8; i++)
+                       QLCWR32(adapter, reg + (i * 0x4), 0x0);
+       }
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0)
+                       reg = QLC_83XX_PORT0_TC_MC_REG;
+               else if (j == 1)
+                       reg = QLC_83XX_PORT1_TC_MC_REG;
+
+               for (i = 0; i < 4; i++)
+                       QLCWR32(adapter, reg + (i * 0x4), 0x03FF03FF);
+       }
+
+       QLCWR32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, 0);
+       QLCWR32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, 0);
+       dev_info(&adapter->pdev->dev,
+                "Disabled pause frames successfully on all ports\n");
+       qlcnic_83xx_unlock_driver(adapter);
+}
+
+static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
+{
+       u32 heartbeat, peg_status;
+       int retries, ret = -EIO;
+
+       retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
+       p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev,
+                                              QLCNIC_PEG_ALIVE_COUNTER);
+
+       do {
+               msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
+               heartbeat = QLC_SHARED_REG_RD32(p_dev,
+                                               QLCNIC_PEG_ALIVE_COUNTER);
+               if (heartbeat != p_dev->heartbeat) {
+                       ret = QLCNIC_RCODE_SUCCESS;
+                       break;
+               }
+       } while (--retries);
+
+       if (ret) {
+               dev_err(&p_dev->pdev->dev, "firmware hang detected\n");
+               qlcnic_83xx_disable_pause_frames(p_dev);
+               peg_status = QLC_SHARED_REG_RD32(p_dev,
+                                                QLCNIC_PEG_HALT_STATUS1);
+               dev_info(&p_dev->pdev->dev, "Dumping HW/FW registers\n"
+                        "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+                        "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+                        "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+                        "PEG_NET_4_PC: 0x%x\n", peg_status,
+                        QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4));
+
+               if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
+                       dev_err(&p_dev->pdev->dev,
+                               "Device is being reset err code 0x00006700.\n");
+       }
+
+       return ret;
+}
+
+static int qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev)
+{
+       int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
+       u32 val;
+
+       do {
+               val = QLC_SHARED_REG_RD32(p_dev, QLCNIC_CMDPEG_STATE);
+               if (val == QLC_83XX_CMDPEG_COMPLETE)
+                       return 0;
+               msleep(QLCNIC_CMDPEG_CHECK_DELAY);
+       } while (--retries);
+
+       dev_err(&p_dev->pdev->dev, "%s: failed, state = 0x%x\n", __func__, val);
+       return -EIO;
+}
+
+int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
+{
+       int err;
+
+       err = qlcnic_83xx_check_cmd_peg_status(p_dev);
+       if (err)
+               return err;
+
+       err = qlcnic_83xx_check_heartbeat(p_dev);
+       if (err)
+               return err;
+
+       return err;
+}
+
+static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
+                               int duration, u32 mask, u32 status)
+{
+       u32 value;
+       int timeout_error;
+       u8 retries;
+
+       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+       retries = duration / 10;
+
+       do {
+               if ((value & mask) != status) {
+                       timeout_error = 1;
+                       msleep(duration / 10);
+                       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+               } else {
+                       timeout_error = 0;
+                       break;
+               }
+       } while (retries--);
+
+       if (timeout_error) {
+               p_dev->ahw->reset.seq_error++;
+               dev_err(&p_dev->pdev->dev,
+                       "%s: Timeout Err, entry_num = %d\n",
+                       __func__, p_dev->ahw->reset.seq_index);
+               dev_err(&p_dev->pdev->dev,
+                       "0x%08x 0x%08x 0x%08x\n",
+                       value, mask, status);
+       }
+
+       return timeout_error;
+}
+
+static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)
+{
+       u32 sum = 0;
+       u16 *buff = (u16 *)p_dev->ahw->reset.buff;
+       int count = p_dev->ahw->reset.hdr->size / sizeof(u16);
+
+       while (count-- > 0)
+               sum += *buff++;
+
+       while (sum >> 16)
+               sum = (sum & 0xFFFF) + (sum >> 16);
+
+       if (~sum) {
+               return 0;
+       } else {
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+               return -1;
+       }
+}
+
+int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
+{
+       u8 *p_buff;
+       u32 addr, count;
+       struct qlcnic_hardware_context *ahw = p_dev->ahw;
+
+       ahw->reset.seq_error = 0;
+       ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
+
+       if (p_dev->ahw->reset.buff == NULL) {
+               dev_err(&p_dev->pdev->dev,
+                       "%s: resource allocation failed\n", __func__);
+               return -ENOMEM;
+       }
+       p_buff = p_dev->ahw->reset.buff;
+       addr = QLC_83XX_RESET_TEMPLATE_ADDR;
+       count = sizeof(struct qlc_83xx_reset_hdr) / sizeof(u32);
+
+       /* Copy template header from flash */
+       if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
+               dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+               return -EIO;
+       }
+       ahw->reset.hdr = (struct qlc_83xx_reset_hdr *)ahw->reset.buff;
+       addr = QLC_83XX_RESET_TEMPLATE_ADDR + ahw->reset.hdr->hdr_size;
+       p_buff = ahw->reset.buff + ahw->reset.hdr->hdr_size;
+       count = (ahw->reset.hdr->size - ahw->reset.hdr->hdr_size) / sizeof(u32);
+
+       /* Copy rest of the template */
+       if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
+               dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+               return -EIO;
+       }
+
+       if (qlcnic_83xx_reset_template_checksum(p_dev))
+               return -EIO;
+       /* Get Stop, Start and Init command offsets */
+       ahw->reset.init_offset = ahw->reset.buff + ahw->reset.hdr->init_offset;
+       ahw->reset.start_offset = ahw->reset.buff +
+                                 ahw->reset.hdr->start_offset;
+       ahw->reset.stop_offset = ahw->reset.buff + ahw->reset.hdr->hdr_size;
+       return 0;
+}
+
+/* Read Write HW register command */
+static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
+                                          u32 raddr, u32 waddr)
+{
+       int value;
+
+       value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+       qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+}
+
+/* Read Modify Write HW register command */
+static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
+                                   u32 raddr, u32 waddr,
+                                   struct qlc_83xx_rmw *p_rmw_hdr)
+{
+       int value;
+
+       if (p_rmw_hdr->index_a)
+               value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
+       else
+               value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+
+       value &= p_rmw_hdr->mask;
+       value <<= p_rmw_hdr->shl;
+       value >>= p_rmw_hdr->shr;
+       value |= p_rmw_hdr->or_value;
+       value ^= p_rmw_hdr->xor_value;
+       qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+}
+
+/* Write HW register command */
+static void qlcnic_83xx_write_list(struct qlcnic_adapter *p_dev,
+                                  struct qlc_83xx_entry_hdr *p_hdr)
+{
+       int i;
+       struct qlc_83xx_entry *entry;
+
+       entry = (struct qlc_83xx_entry *)((char *)p_hdr +
+                                         sizeof(struct qlc_83xx_entry_hdr));
+
+       for (i = 0; i < p_hdr->count; i++, entry++) {
+               qlcnic_83xx_wrt_reg_indirect(p_dev, entry->arg1,
+                                            entry->arg2);
+               if (p_hdr->delay)
+                       udelay((u32)(p_hdr->delay));
+       }
+}
+
+/* Read and Write instruction */
+static void qlcnic_83xx_read_write_list(struct qlcnic_adapter *p_dev,
+                                       struct qlc_83xx_entry_hdr *p_hdr)
+{
+       int i;
+       struct qlc_83xx_entry *entry;
+
+       entry = (struct qlc_83xx_entry *)((char *)p_hdr +
+                                         sizeof(struct qlc_83xx_entry_hdr));
+
+       for (i = 0; i < p_hdr->count; i++, entry++) {
+               qlcnic_83xx_read_write_crb_reg(p_dev, entry->arg1,
+                                              entry->arg2);
+               if (p_hdr->delay)
+                       udelay((u32)(p_hdr->delay));
+       }
+}
+
+/* Poll HW register command */
+static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
+                                 struct qlc_83xx_entry_hdr *p_hdr)
+{
+       long delay;
+       struct qlc_83xx_entry *entry;
+       struct qlc_83xx_poll *poll;
+       int i;
+       unsigned long arg1, arg2;
+
+       poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+                                       sizeof(struct qlc_83xx_entry_hdr));
+
+       entry = (struct qlc_83xx_entry *)((char *)poll +
+                                         sizeof(struct qlc_83xx_poll));
+       delay = (long)p_hdr->delay;
+
+       if (!delay) {
+               for (i = 0; i < p_hdr->count; i++, entry++)
+                       qlcnic_83xx_poll_reg(p_dev, entry->arg1,
+                                            delay, poll->mask,
+                                            poll->status);
+       } else {
+               for (i = 0; i < p_hdr->count; i++, entry++) {
+                       arg1 = entry->arg1;
+                       arg2 = entry->arg2;
+                       if (delay) {
+                               if (qlcnic_83xx_poll_reg(p_dev,
+                                                        arg1, delay,
+                                                        poll->mask,
+                                                        poll->status)){
+                                       qlcnic_83xx_rd_reg_indirect(p_dev,
+                                                                   arg1);
+                                       qlcnic_83xx_rd_reg_indirect(p_dev,
+                                                                   arg2);
+                               }
+                       }
+               }
+       }
+}
+
+/* Poll and write HW register command */
+static void qlcnic_83xx_poll_write_list(struct qlcnic_adapter *p_dev,
+                                       struct qlc_83xx_entry_hdr *p_hdr)
+{
+       int i;
+       long delay;
+       struct qlc_83xx_quad_entry *entry;
+       struct qlc_83xx_poll *poll;
+
+       poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+                                       sizeof(struct qlc_83xx_entry_hdr));
+       entry = (struct qlc_83xx_quad_entry *)((char *)poll +
+                                              sizeof(struct qlc_83xx_poll));
+       delay = (long)p_hdr->delay;
+
+       for (i = 0; i < p_hdr->count; i++, entry++) {
+               qlcnic_83xx_wrt_reg_indirect(p_dev, entry->dr_addr,
+                                            entry->dr_value);
+               qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
+                                            entry->ar_value);
+               if (delay)
+                       qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
+                                            poll->mask, poll->status);
+       }
+}
+
+/* Read Modify Write register command */
+static void qlcnic_83xx_read_modify_write(struct qlcnic_adapter *p_dev,
+                                         struct qlc_83xx_entry_hdr *p_hdr)
+{
+       int i;
+       struct qlc_83xx_entry *entry;
+       struct qlc_83xx_rmw *rmw_hdr;
+
+       rmw_hdr = (struct qlc_83xx_rmw *)((char *)p_hdr +
+                                         sizeof(struct qlc_83xx_entry_hdr));
+
+       entry = (struct qlc_83xx_entry *)((char *)rmw_hdr +
+                                         sizeof(struct qlc_83xx_rmw));
+
+       for (i = 0; i < p_hdr->count; i++, entry++) {
+               qlcnic_83xx_rmw_crb_reg(p_dev, entry->arg1,
+                                       entry->arg2, rmw_hdr);
+               if (p_hdr->delay)
+                       udelay((u32)(p_hdr->delay));
+       }
+}
+
+static void qlcnic_83xx_pause(struct qlc_83xx_entry_hdr *p_hdr)
+{
+       if (p_hdr->delay)
+               mdelay((u32)((long)p_hdr->delay));
+}
+
+/* Read and poll register command */
+static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
+                                      struct qlc_83xx_entry_hdr *p_hdr)
+{
+       long delay;
+       int index, i, j;
+       struct qlc_83xx_quad_entry *entry;
+       struct qlc_83xx_poll *poll;
+       unsigned long addr;
+
+       poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+                                       sizeof(struct qlc_83xx_entry_hdr));
+
+       entry = (struct qlc_83xx_quad_entry *)((char *)poll +
+                                              sizeof(struct qlc_83xx_poll));
+       delay = (long)p_hdr->delay;
+
+       for (i = 0; i < p_hdr->count; i++, entry++) {
+               qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
+                                            entry->ar_value);
+               if (delay) {
+                       if (!qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
+                                                 poll->mask, poll->status)){
+                               index = p_dev->ahw->reset.array_index;
+                               addr = entry->dr_addr;
+                               j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+                               p_dev->ahw->reset.array[index++] = j;
+
+                               if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
+                                       p_dev->ahw->reset.array_index = 1;
+                       }
+               }
+       }
+}
+
+static inline void qlcnic_83xx_seq_end(struct qlcnic_adapter *p_dev)
+{
+       p_dev->ahw->reset.seq_end = 1;
+}
+
+static void qlcnic_83xx_template_end(struct qlcnic_adapter *p_dev)
+{
+       p_dev->ahw->reset.template_end = 1;
+       if (p_dev->ahw->reset.seq_error == 0)
+               dev_err(&p_dev->pdev->dev,
+                       "HW restart process completed successfully.\n");
+       else
+               dev_err(&p_dev->pdev->dev,
+                       "HW restart completed with timeout errors.\n");
+}
+
+/**
+* qlcnic_83xx_exec_template_cmd
+*
+* @p_dev: adapter structure
+* @p_buff: Poiter to instruction template
+*
+* Template provides instructions to stop, restart and initalize firmware.
+* These instructions are abstracted as a series of read, write and
+* poll operations on hardware registers. Register information and operation
+* specifics are not exposed to the driver. Driver reads the template from
+* flash and executes the instructions located at pre-defined offsets.
+*
+* Returns: None
+* */
+static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev,
+                                         char *p_buff)
+{
+       int index, entries;
+       struct qlc_83xx_entry_hdr *p_hdr;
+       char *entry = p_buff;
+
+       p_dev->ahw->reset.seq_end = 0;
+       p_dev->ahw->reset.template_end = 0;
+       entries = p_dev->ahw->reset.hdr->entries;
+       index = p_dev->ahw->reset.seq_index;
+
+       for (; (!p_dev->ahw->reset.seq_end) && (index < entries); index++) {
+               p_hdr = (struct qlc_83xx_entry_hdr *)entry;
+
+               switch (p_hdr->cmd) {
+               case QLC_83XX_OPCODE_NOP:
+                       break;
+               case QLC_83XX_OPCODE_WRITE_LIST:
+                       qlcnic_83xx_write_list(p_dev, p_hdr);
+                       break;
+               case QLC_83XX_OPCODE_READ_WRITE_LIST:
+                       qlcnic_83xx_read_write_list(p_dev, p_hdr);
+                       break;
+               case QLC_83XX_OPCODE_POLL_LIST:
+                       qlcnic_83xx_poll_list(p_dev, p_hdr);
+                       break;
+               case QLC_83XX_OPCODE_POLL_WRITE_LIST:
+                       qlcnic_83xx_poll_write_list(p_dev, p_hdr);
+                       break;
+               case QLC_83XX_OPCODE_READ_MODIFY_WRITE:
+                       qlcnic_83xx_read_modify_write(p_dev, p_hdr);
+                       break;
+               case QLC_83XX_OPCODE_SEQ_PAUSE:
+                       qlcnic_83xx_pause(p_hdr);
+                       break;
+               case QLC_83XX_OPCODE_SEQ_END:
+                       qlcnic_83xx_seq_end(p_dev);
+                       break;
+               case QLC_83XX_OPCODE_TMPL_END:
+                       qlcnic_83xx_template_end(p_dev);
+                       break;
+               case QLC_83XX_OPCODE_POLL_READ_LIST:
+                       qlcnic_83xx_poll_read_list(p_dev, p_hdr);
+                       break;
+               default:
+                       dev_err(&p_dev->pdev->dev,
+                               "%s: Unknown opcode 0x%04x in template %d\n",
+                               __func__, p_hdr->cmd, index);
+                       break;
+               }
+               entry += p_hdr->size;
+       }
+       p_dev->ahw->reset.seq_index = index;
+}
+
+static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
+{
+       p_dev->ahw->reset.seq_index = 0;
+
+       qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.stop_offset);
+       if (p_dev->ahw->reset.seq_end != 1)
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void qlcnic_83xx_start_hw(struct qlcnic_adapter *p_dev)
+{
+       qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.start_offset);
+       if (p_dev->ahw->reset.template_end != 1)
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
+{
+       qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.init_offset);
+       if (p_dev->ahw->reset.seq_end != 1)
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       if (request_firmware(&adapter->ahw->fw_info.fw,
+                            QLC_83XX_FW_FILE_NAME, &(adapter->pdev->dev))) {
+               dev_err(&adapter->pdev->dev,
+                       "No file FW image, loading flash FW image.\n");
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+                                   QLC_83XX_BOOT_FROM_FLASH);
+       } else {
+               if (qlcnic_83xx_copy_fw_file(adapter))
+                       return err;
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+                                   QLC_83XX_BOOT_FROM_FILE);
+       }
+
+       return 0;
+}
+
+static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       int err = -EIO;
+
+       qlcnic_83xx_stop_hw(adapter);
+
+       /* Collect FW register dump if required */
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+       if (!(val & QLC_83XX_IDC_GRACEFULL_RESET))
+               qlcnic_dump_fw(adapter);
+       qlcnic_83xx_init_hw(adapter);
+
+       if (qlcnic_83xx_copy_bootloader(adapter))
+               return err;
+       /* Boot either flash image or firmware image from host file system */
+       if (qlcnic_load_fw_file) {
+               if (qlcnic_83xx_load_fw_image_from_host(adapter))
+                       return err;
+       } else {
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+                                   QLC_83XX_BOOT_FROM_FLASH);
+       }
+
+       qlcnic_83xx_start_hw(adapter);
+       if (qlcnic_83xx_check_hw_status(adapter))
+               return -EIO;
+
+       return 0;
+}
+
+/**
+* qlcnic_83xx_config_default_opmode
+*
+* @adapter: adapter structure
+*
+* Configure default driver operating mode
+*
+* Returns: Error code or Success(0)
+* */
+int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *adapter)
+{
+       u32 op_mode;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       qlcnic_get_func_no(adapter);
+       op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE);
+
+       if (op_mode == QLC_83XX_DEFAULT_OPMODE) {
+               adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver;
+               ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+       } else {
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)
+{
+       int err;
+       struct qlcnic_info nic_info;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       memset(&nic_info, 0, sizeof(struct qlcnic_info));
+       err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
+       if (err)
+               return -EIO;
+
+       ahw->physical_port = (u8) nic_info.phys_port;
+       ahw->switch_mode = nic_info.switch_mode;
+       ahw->max_tx_ques = nic_info.max_tx_ques;
+       ahw->max_rx_ques = nic_info.max_rx_ques;
+       ahw->capabilities = nic_info.capabilities;
+       ahw->max_mac_filters = nic_info.max_mac_filters;
+       ahw->max_mtu = nic_info.max_mtu;
+
+       if (ahw->capabilities & BIT_23)
+               ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE;
+       else
+               ahw->nic_mode = QLC_83XX_DEFAULT_MODE;
+
+       return ahw->nic_mode;
+}
+
+static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
+{
+       int ret;
+
+       ret = qlcnic_83xx_get_nic_configuration(adapter);
+       if (ret == -EIO)
+               return -EIO;
+
+       if (ret == QLC_83XX_VIRTUAL_NIC_MODE) {
+               if (qlcnic_83xx_config_vnic_opmode(adapter))
+                       return -EIO;
+       } else if (ret == QLC_83XX_DEFAULT_MODE) {
+               if (qlcnic_83xx_config_default_opmode(adapter))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static void qlcnic_83xx_config_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (ahw->port_type == QLCNIC_XGBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+       } else if (ahw->port_type == QLCNIC_GBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+       }
+       adapter->num_txd = MAX_CMD_DESCRIPTORS;
+       adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       qlcnic_83xx_get_minidump_template(adapter);
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d\n",
+                adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+#define IS_QLC_83XX_USED(a, b, c) (((1 << a->portnum) & b) || ((c >> 6) & 0x1))
+static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_args cmd;
+       u32 presence_mask, audit_mask;
+       int status;
+
+       presence_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+       audit_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
+
+       if (IS_QLC_83XX_USED(adapter, presence_mask, audit_mask)) {
+               qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+               cmd.req.arg[1] = BIT_31;
+               status = qlcnic_issue_cmd(adapter, &cmd);
+               if (status)
+                       dev_err(&adapter->pdev->dev,
+                               "Failed to clean up the function resources\n");
+               qlcnic_free_mbx_args(&cmd);
+       }
+}
+
+int qlcnic_83xx_init(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (qlcnic_83xx_check_hw_status(adapter))
+               return -EIO;
+
+       /* Initilaize 83xx mailbox spinlock */
+       spin_lock_init(&ahw->mbx_lock);
+
+       set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+       qlcnic_83xx_clear_function_resources(adapter);
+
+       if (!qlcnic_83xx_read_flash_descriptor_table(adapter))
+               qlcnic_83xx_read_flash_mfg_id(adapter);
+
+       if (qlcnic_83xx_idc_init(adapter))
+               return -EIO;
+
+       /* Configure default, SR-IOV or Virtual NIC mode of operation */
+       if (qlcnic_83xx_configure_opmode(adapter))
+               return -EIO;
+
+       /* Perform operating mode specific initialization */
+       if (adapter->nic_ops->init_driver(adapter))
+               return -EIO;
+
+       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
+       /* register for NIC IDC AEN Events */
+       qlcnic_83xx_register_nic_idc_func(adapter, 1);
+
+       /* Periodically monitor device status */
+       qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
+
+       return adapter->ahw->idc.err_code;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
new file mode 100644 (file)
index 0000000..d394471
--- /dev/null
@@ -0,0 +1,216 @@
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+       QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_OPER);
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+       ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+       u8 id;
+       int i, ret = -EBUSY;
+       u32 data = QLCNIC_MGMT_FUNC;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (qlcnic_83xx_lock_driver(adapter))
+               return ret;
+
+       if (qlcnic_config_npars) {
+               for (i = 0; i < ahw->act_pci_func; i++) {
+                       id = adapter->npars[i].pci_func;
+                       if (id == ahw->pci_func)
+                               continue;
+                       data |= qlcnic_config_npars &
+                               QLC_83XX_SET_FUNC_OPMODE(0x3, id);
+               }
+       } else {
+               data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+               data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
+                      QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
+                                               ahw->pci_func);
+       }
+       QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
+
+       qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static void
+qlcnic_83xx_config_vnic_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (ahw->port_type == QLCNIC_XGBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+       } else if (ahw->port_type == QLCNIC_GBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+       }
+       adapter->num_txd = MAX_CMD_DESCRIPTORS;
+       adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+
+/**
+ * qlcnic_83xx_init_mgmt_vnic
+ *
+ * @adapter: adapter structure
+ * Management virtual NIC sets the operational mode of other vNIC's and
+ * configures embedded switch (ESWITCH).
+ * Returns: Success(0) or error code.
+ *
+ **/
+static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED)) {
+               if (qlcnic_init_pci_info(adapter))
+                       return err;
+
+               if (qlcnic_83xx_set_vnic_opmode(adapter))
+                       return err;
+
+               if (qlcnic_set_default_offload_settings(adapter))
+                       return err;
+       } else {
+               if (qlcnic_reset_npar_config(adapter))
+                       return err;
+       }
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+       qlcnic_83xx_enable_vnic_mode(adapter, 1);
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n",
+                adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+static int qlcnic_83xx_init_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       dev_info(&adapter->pdev->dev,
+                "HAL Version: %d, Privileged function\n",
+                adapter->ahw->fw_hal_version);
+       return 0;
+}
+
+static int qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       qlcnic_83xx_get_fw_version(adapter);
+       if (qlcnic_set_eswitch_port_config(adapter))
+               return err;
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d, Virtual function\n",
+                adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_vnic_opmode
+ *
+ * @adapter: adapter structure
+ * Identify virtual NIC operational modes.
+ *
+ * Returns: Success(0) or error code.
+ *
+ **/
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+       u32 op_mode, priv_level;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_nic_template *nic_ops = adapter->nic_ops;
+
+       qlcnic_get_func_no(adapter);
+       op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+       if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+                                                        ahw->pci_func);
+
+       if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+               ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+               nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic;
+       } else if (priv_level == QLCNIC_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_PRIV_FUNC;
+               ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry;
+               nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic;
+       } else if (priv_level == QLCNIC_MGMT_FUNC) {
+               ahw->op_mode = QLCNIC_MGMT_FUNC;
+               ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+               nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic;
+       } else {
+               return -EIO;
+       }
+
+       if (ahw->capabilities & BIT_23)
+               adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+       else
+               adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+       adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+       adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+
+       return 0;
+}
index b14b8f0787ea10cfce41a77698b2239bb0b56f08..7372964d3a765729c64ec54231d023b7e27aa50f 100644 (file)
@@ -7,6 +7,86 @@
 
 #include "qlcnic.h"
 
+static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
+       {QLCNIC_CMD_CREATE_RX_CTX, 4, 1},
+       {QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},
+       {QLCNIC_CMD_CREATE_TX_CTX, 4, 1},
+       {QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},
+       {QLCNIC_CMD_INTRPT_TEST, 4, 1},
+       {QLCNIC_CMD_SET_MTU, 4, 1},
+       {QLCNIC_CMD_READ_PHY, 4, 2},
+       {QLCNIC_CMD_WRITE_PHY, 5, 1},
+       {QLCNIC_CMD_READ_HW_REG, 4, 1},
+       {QLCNIC_CMD_GET_FLOW_CTL, 4, 2},
+       {QLCNIC_CMD_SET_FLOW_CTL, 4, 1},
+       {QLCNIC_CMD_READ_MAX_MTU, 4, 2},
+       {QLCNIC_CMD_READ_MAX_LRO, 4, 2},
+       {QLCNIC_CMD_MAC_ADDRESS, 4, 3},
+       {QLCNIC_CMD_GET_PCI_INFO, 4, 1},
+       {QLCNIC_CMD_GET_NIC_INFO, 4, 1},
+       {QLCNIC_CMD_SET_NIC_INFO, 4, 1},
+       {QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},
+       {QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},
+       {QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},
+       {QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},
+       {QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},
+       {QLCNIC_CMD_GET_MAC_STATS, 4, 1},
+       {QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},
+       {QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},
+       {QLCNIC_CMD_CONFIG_PORT, 4, 1},
+       {QLCNIC_CMD_TEMP_SIZE, 4, 4},
+       {QLCNIC_CMD_GET_TEMP_HDR, 4, 1},
+       {QLCNIC_CMD_SET_DRV_VER, 4, 1},
+};
+
+static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)
+{
+       return (ahw->pci_func & 0xff) | ((ahw->fw_hal_version & 0xff) << 8) |
+              (0xcafe << 16);
+}
+
+/* Allocate mailbox registers */
+int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+                              struct qlcnic_adapter *adapter, u32 type)
+{
+       int i, size;
+       const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+       mbx_tbl = qlcnic_mbx_tbl;
+       size = ARRAY_SIZE(qlcnic_mbx_tbl);
+       for (i = 0; i < size; i++) {
+               if (type == mbx_tbl[i].cmd) {
+                       mbx->req.num = mbx_tbl[i].in_args;
+                       mbx->rsp.num = mbx_tbl[i].out_args;
+                       mbx->req.arg = kcalloc(mbx->req.num,
+                                              sizeof(u32), GFP_ATOMIC);
+                       if (!mbx->req.arg)
+                               return -ENOMEM;
+                       mbx->rsp.arg = kcalloc(mbx->rsp.num,
+                                              sizeof(u32), GFP_ATOMIC);
+                       if (!mbx->rsp.arg) {
+                               kfree(mbx->req.arg);
+                               mbx->req.arg = NULL;
+                               return -ENOMEM;
+                       }
+                       memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+                       memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+                       mbx->req.arg[0] = type;
+                       break;
+               }
+       }
+       return 0;
+}
+
+/* Free up mailbox registers */
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd)
+{
+       kfree(cmd->req.arg);
+       cmd->req.arg = NULL;
+       kfree(cmd->rsp.arg);
+       cmd->rsp.arg = NULL;
+}
+
 static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
 {
        int i;
@@ -38,194 +118,102 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
        return rsp;
 }
 
-void
-qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd)
+int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
+                         struct qlcnic_cmd_args *cmd)
 {
+       int i;
        u32 rsp;
        u32 signature;
        struct pci_dev *pdev = adapter->pdev;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       signature = QLCNIC_CDRP_SIGNATURE_MAKE(ahw->pci_func,
-                                              adapter->ahw->fw_hal_version);
+       signature = qlcnic_get_cmd_signature(ahw);
 
        /* Acquire semaphore before accessing CRB */
        if (qlcnic_api_lock(adapter)) {
-               cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
-               return;
+               cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+               return cmd->rsp.arg[0];
        }
 
        QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
-       QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, cmd->req.arg1);
-       QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, cmd->req.arg2);
-       QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, cmd->req.arg3);
+       for (i = 1; i < QLCNIC_CDRP_MAX_ARGS; i++)
+               QLCWR32(adapter, QLCNIC_CDRP_ARG(i), cmd->req.arg[i]);
        QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET,
-               QLCNIC_CDRP_FORM_CMD(cmd->req.cmd));
-
+               QLCNIC_CDRP_FORM_CMD(cmd->req.arg[0]));
        rsp = qlcnic_poll_rsp(adapter);
 
        if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
-               dev_err(&pdev->dev, "CDRP response timeout.\n");
-               cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
+               dev_err(&pdev->dev, "card response timeout.\n");
+               cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
        } else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
-               cmd->rsp.cmd = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
-               switch (cmd->rsp.cmd) {
-               case QLCNIC_RCODE_INVALID_ARGS:
-                       dev_err(&pdev->dev, "CDRP invalid args: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_NOT_SUPPORTED:
-               case QLCNIC_RCODE_NOT_IMPL:
-                       dev_err(&pdev->dev,
-                               "CDRP command not supported: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_NOT_PERMITTED:
-                       dev_err(&pdev->dev,
-                               "CDRP requested action not permitted: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_INVALID:
-                       dev_err(&pdev->dev,
-                               "CDRP invalid or unknown cmd received: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_TIMEOUT:
-                       dev_err(&pdev->dev, "CDRP command timeout: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               default:
-                       dev_err(&pdev->dev, "CDRP command failed: 0x%x.\n",
-                               cmd->rsp.cmd);
-               }
-       } else if (rsp == QLCNIC_CDRP_RSP_OK) {
-               cmd->rsp.cmd = QLCNIC_RCODE_SUCCESS;
-               if (cmd->rsp.arg2)
-                       cmd->rsp.arg2 = QLCRD32(adapter,
-                               QLCNIC_ARG2_CRB_OFFSET);
-               if (cmd->rsp.arg3)
-                       cmd->rsp.arg3 = QLCRD32(adapter,
-                               QLCNIC_ARG3_CRB_OFFSET);
-       }
-       if (cmd->rsp.arg1)
-               cmd->rsp.arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+               cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
+               dev_err(&pdev->dev, "failed card response code:0x%x\n",
+                       cmd->rsp.arg[0]);
+       } else if (rsp == QLCNIC_CDRP_RSP_OK)
+               cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
+
+       for (i = 1; i < cmd->rsp.num; i++)
+               cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i));
 
        /* Release semaphore */
        qlcnic_api_unlock(adapter);
-
-}
-
-static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
-{
-       uint64_t sum = 0;
-       int count = temp_size / sizeof(uint32_t);
-       while (count-- > 0)
-               sum += *temp_buffer++;
-       while (sum >> 32)
-               sum = (sum & 0xFFFFFFFF) + (sum >> 32);
-       return ~sum;
+       return cmd->rsp.arg[0];
 }
 
-int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter)
 {
-       int err, i;
-       void *tmp_addr;
-       u32 temp_size, version, csum, *template;
-       __le32 *tmp_buf;
        struct qlcnic_cmd_args cmd;
-       struct qlcnic_hardware_context *ahw;
-       struct qlcnic_dump_template_hdr *tmpl_hdr;
-       dma_addr_t tmp_addr_t = 0;
-
-       ahw = adapter->ahw;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_TEMP_SIZE;
-       memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
-       qlcnic_issue_cmd(adapter, &cmd);
-       if (cmd.rsp.cmd != QLCNIC_RCODE_SUCCESS) {
-               dev_info(&adapter->pdev->dev,
-                       "Can't get template size %d\n", cmd.rsp.cmd);
-               err = -EIO;
-               return err;
-       }
-       temp_size = cmd.rsp.arg2;
-       version = cmd.rsp.arg3;
-       dev_info(&adapter->pdev->dev,
-                "minidump template version = 0x%x", version);
-       if (!temp_size)
-               return -EIO;
+       u32 arg1, arg2, arg3;
+       char drv_string[12];
+       int err = 0;
 
-       tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
-                       &tmp_addr_t, GFP_KERNEL);
-       if (!tmp_addr) {
-               dev_err(&adapter->pdev->dev,
-                       "Can't get memory for FW dump template\n");
-               return -ENOMEM;
-       }
-       memset(&cmd.rsp, 0, sizeof(struct _cdrp_cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_TEMP_HDR;
-       cmd.req.arg1 = LSD(tmp_addr_t);
-       cmd.req.arg2 = MSD(tmp_addr_t);
-       cmd.req.arg3 = temp_size;
-       qlcnic_issue_cmd(adapter, &cmd);
-
-       err = cmd.rsp.cmd;
-       if (err != QLCNIC_RCODE_SUCCESS) {
-               dev_err(&adapter->pdev->dev,
-                       "Failed to get mini dump template header %d\n", err);
-               err = -EIO;
-               goto error;
-       }
-       ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
-       if (!ahw->fw_dump.tmpl_hdr) {
-               err = -EIO;
-               goto error;
-       }
-       tmp_buf = tmp_addr;
-       template = (u32 *) ahw->fw_dump.tmpl_hdr;
-       for (i = 0; i < temp_size/sizeof(u32); i++)
-               *template++ = __le32_to_cpu(*tmp_buf++);
+       memset(drv_string, 0, sizeof(drv_string));
+       snprintf(drv_string, sizeof(drv_string), "%d"".""%d"".""%d",
+                _QLCNIC_LINUX_MAJOR, _QLCNIC_LINUX_MINOR,
+                _QLCNIC_LINUX_SUBVERSION);
 
-       csum = qlcnic_temp_checksum((u32 *)ahw->fw_dump.tmpl_hdr, temp_size);
-       if (csum) {
-               dev_err(&adapter->pdev->dev,
-                       "Template header checksum validation failed\n");
-               err = -EIO;
-               goto error;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_DRV_VER);
+       memcpy(&arg1, drv_string, sizeof(u32));
+       memcpy(&arg2, drv_string + 4, sizeof(u32));
+       memcpy(&arg3, drv_string + 8, sizeof(u32));
+
+       cmd.req.arg[1] = arg1;
+       cmd.req.arg[2] = arg2;
+       cmd.req.arg[3] = arg3;
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                        "Failed to set driver version in firmware\n");
+               return -EIO;
        }
 
-       tmpl_hdr = ahw->fw_dump.tmpl_hdr;
-       tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
-       ahw->fw_dump.enable = 1;
-error:
-       dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
-       return err;
+       return 0;
 }
 
 int
 qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
 {
+       int err = 0;
        struct qlcnic_cmd_args cmd;
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_SET_MTU;
-       cmd.req.arg1 = recv_ctx->context_id;
-       cmd.req.arg2 = mtu;
-       cmd.req.arg3 = 0;
-       if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
-               qlcnic_issue_cmd(adapter, &cmd);
-               if (cmd.rsp.cmd) {
-                       dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
-                       return -EIO;
-               }
-       }
+       if (recv_ctx->state != QLCNIC_HOST_CTX_STATE_ACTIVE)
+               return err;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_MTU);
+       cmd.req.arg[1] = recv_ctx->context_id;
+       cmd.req.arg[2] = mtu;
 
-       return 0;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
+               err = -EIO;
+       }
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 }
 
-static int
-qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 {
        void *addr;
        struct qlcnic_hostrq_rx_ctx *prq;
@@ -242,10 +230,10 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
        u64 phys_addr;
 
        u8 i, nrds_rings, nsds_rings;
+       u16 temp_u16;
        size_t rq_size, rsp_size;
        u32 cap, reg, val, reg2;
        int err;
-       u16 temp;
 
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
@@ -279,11 +267,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
                                                | QLCNIC_CAP0_VALIDOFF);
        cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
 
-       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
-               cap |= QLCNIC_CAP0_LRO_MSS;
-
-       temp = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
-       prq->valid_field_offset = cpu_to_le16(temp);
+       temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
+       prq->valid_field_offset = cpu_to_le16(temp_u16);
        prq->txrx_sds_binding = nsds_rings - 1;
 
        prq->capabilities[0] = cpu_to_le32(cap);
@@ -329,20 +314,17 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
        }
 
        phys_addr = hostrq_phys_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = (u32) (phys_addr >> 32);
-       cmd.req.arg2 = (u32) (phys_addr & 0xffffffff);
-       cmd.req.arg3 = rq_size;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_RX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX);
+       cmd.req.arg[1] = MSD(phys_addr);
+       cmd.req.arg[2] = LSD(phys_addr);
+       cmd.req.arg[3] = rq_size;
+       err = qlcnic_issue_cmd(adapter, &cmd);
        if (err) {
                dev_err(&adapter->pdev->dev,
                        "Failed to create rx ctx in firmware%d\n", err);
                goto out_free_rsp;
        }
 
-
        prsp_rds = ((struct qlcnic_cardrsp_rds_ring *)
                         &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
 
@@ -373,6 +355,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 out_free_rsp:
        dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
                cardrsp_phys_addr);
+       qlcnic_free_mbx_args(&cmd);
 out_free_rq:
        dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
        return err;
@@ -381,24 +364,24 @@ out_free_rq:
 static void
 qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
 {
+       int err;
        struct qlcnic_cmd_args cmd;
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = recv_ctx->context_id;
-       cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
-       cmd.req.arg3 = 0;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_RX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       if (cmd.rsp.cmd)
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX);
+       cmd.req.arg[1] = recv_ctx->context_id;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
                dev_err(&adapter->pdev->dev,
                        "Failed to destroy rx ctx in firmware\n");
 
        recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
+       qlcnic_free_mbx_args(&cmd);
 }
 
-static int
-qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
+                                    struct qlcnic_host_tx_ring *tx_ring,
+                                    int ring)
 {
        struct qlcnic_hostrq_tx_ctx     *prq;
        struct qlcnic_hostrq_cds_ring   *prq_cds;
@@ -410,7 +393,6 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
        int     err;
        u64     phys_addr;
        dma_addr_t      rq_phys_addr, rsp_phys_addr;
-       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 
        /* reset host resources */
        tx_ring->producer = 0;
@@ -445,9 +427,9 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
 
        prq->host_int_crb_mode =
                cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+       prq->msi_index = 0;
 
        prq->interrupt_ctl = 0;
-       prq->msi_index = 0;
        prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);
 
        prq_cds = &prq->cds_ring;
@@ -456,19 +438,17 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
        prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
 
        phys_addr = rq_phys_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = (u32)(phys_addr >> 32);
-       cmd.req.arg2 = ((u32)phys_addr & 0xffffffff);
-       cmd.req.arg3 = rq_size;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_TX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+       cmd.req.arg[1] = MSD(phys_addr);
+       cmd.req.arg[2] = LSD(phys_addr);
+       cmd.req.arg[3] = rq_size;
+       err = qlcnic_issue_cmd(adapter, &cmd);
 
        if (err == QLCNIC_RCODE_SUCCESS) {
                temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
                tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp;
-
-               adapter->tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
+               tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
        } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to create tx ctx in firmware%d\n", err);
@@ -476,76 +456,81 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
        }
 
        dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr,
-               rsp_phys_addr);
+                         rsp_phys_addr);
 
 out_free_rq:
        dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr);
+       qlcnic_free_mbx_args(&cmd);
 
        return err;
 }
 
 static void
-qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
+qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter,
+                            struct qlcnic_host_tx_ring *tx_ring)
 {
        struct qlcnic_cmd_args cmd;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = adapter->tx_ring->ctx_id;
-       cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
-       cmd.req.arg3 = 0;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_TX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       if (cmd.rsp.cmd)
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX);
+       cmd.req.arg[1] = tx_ring->ctx_id;
+       if (qlcnic_issue_cmd(adapter, &cmd))
                dev_err(&adapter->pdev->dev,
                        "Failed to destroy tx ctx in firmware\n");
+       qlcnic_free_mbx_args(&cmd);
 }
 
 int
 qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
 {
+       int err;
        struct qlcnic_cmd_args cmd;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = config;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIG_PORT;
-       qlcnic_issue_cmd(adapter, &cmd);
-
-       return cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_PORT);
+       cmd.req.arg[1] = config;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 }
 
 int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
 {
        void *addr;
-       int err;
-       int ring;
+       int err, ring;
        struct qlcnic_recv_context *recv_ctx;
        struct qlcnic_host_rds_ring *rds_ring;
        struct qlcnic_host_sds_ring *sds_ring;
        struct qlcnic_host_tx_ring *tx_ring;
+       __le32 *ptr;
 
        struct pci_dev *pdev = adapter->pdev;
 
        recv_ctx = adapter->recv_ctx;
-       tx_ring = adapter->tx_ring;
 
-       tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev,
-               sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL);
-       if (tx_ring->hw_consumer == NULL) {
-               dev_err(&pdev->dev, "failed to allocate tx consumer\n");
-               return -ENOMEM;
-       }
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               ptr = (__le32 *)dma_alloc_coherent(&pdev->dev, sizeof(u32),
+                                                  &tx_ring->hw_cons_phys_addr,
+                                                  GFP_KERNEL);
 
-       /* cmd desc ring */
-       addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
-                       &tx_ring->phys_addr, GFP_KERNEL);
+               if (ptr == NULL) {
+                       dev_err(&pdev->dev, "failed to allocate tx consumer\n");
+                       return -ENOMEM;
+               }
+               tx_ring->hw_consumer = ptr;
+               /* cmd desc ring */
+               addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
+                                         &tx_ring->phys_addr,
+                                         GFP_KERNEL);
 
-       if (addr == NULL) {
-               dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
-               err = -ENOMEM;
-               goto err_out_free;
-       }
+               if (addr == NULL) {
+                       dev_err(&pdev->dev,
+                               "failed to allocate tx desc ring\n");
+                       err = -ENOMEM;
+                       goto err_out_free;
+               }
 
-       tx_ring->desc_head = addr;
+               tx_ring->desc_head = addr;
+       }
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &recv_ctx->rds_rings[ring];
@@ -584,36 +569,49 @@ err_out_free:
        return err;
 }
 
-
-int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
 {
-       int err;
+       int i, err, ring;
 
-       if (adapter->flags & QLCNIC_NEED_FLR) {
-               pci_reset_function(adapter->pdev);
-               adapter->flags &= ~QLCNIC_NEED_FLR;
+       if (dev->flags & QLCNIC_NEED_FLR) {
+               pci_reset_function(dev->pdev);
+               dev->flags &= ~QLCNIC_NEED_FLR;
        }
 
-       err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+       err = qlcnic_fw_cmd_create_rx_ctx(dev);
        if (err)
                return err;
 
-       err = qlcnic_fw_cmd_create_tx_ctx(adapter);
-       if (err) {
-               qlcnic_fw_cmd_destroy_rx_ctx(adapter);
-               return err;
+       for (ring = 0; ring < dev->max_drv_tx_rings; ring++) {
+               err = qlcnic_fw_cmd_create_tx_ctx(dev,
+                                                 &dev->tx_ring[ring],
+                                                 ring);
+               if (err) {
+                       qlcnic_fw_cmd_destroy_rx_ctx(dev);
+                       if (ring == 0)
+                               return err;
+
+                       for (i = 0; i < ring; i++)
+                               qlcnic_fw_cmd_destroy_tx_ctx(dev,
+                                                            &dev->tx_ring[i]);
+
+                       return err;
+               }
        }
 
-       set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+       set_bit(__QLCNIC_FW_ATTACHED, &dev->state);
        return 0;
 }
 
 void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
 {
+       int ring;
+
        if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
                qlcnic_fw_cmd_destroy_rx_ctx(adapter);
-               qlcnic_fw_cmd_destroy_tx_ctx(adapter);
-
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
+                       qlcnic_fw_cmd_destroy_tx_ctx(adapter,
+                                                    &adapter->tx_ring[ring]);
                /* Allow dma queues to drain after context reset */
                mdelay(20);
        }
@@ -629,20 +627,23 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
 
        recv_ctx = adapter->recv_ctx;
 
-       tx_ring = adapter->tx_ring;
-       if (tx_ring->hw_consumer != NULL) {
-               dma_free_coherent(&adapter->pdev->dev,
-                               sizeof(u32),
-                               tx_ring->hw_consumer,
-                               tx_ring->hw_cons_phys_addr);
-               tx_ring->hw_consumer = NULL;
-       }
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               if (tx_ring->hw_consumer != NULL) {
+                       dma_free_coherent(&adapter->pdev->dev, sizeof(u32),
+                                         tx_ring->hw_consumer,
+                                         tx_ring->hw_cons_phys_addr);
+
+                       tx_ring->hw_consumer = NULL;
+               }
 
-       if (tx_ring->desc_head != NULL) {
-               dma_free_coherent(&adapter->pdev->dev,
-                               TX_DESC_RINGSIZE(tx_ring),
-                               tx_ring->desc_head, tx_ring->phys_addr);
-               tx_ring->desc_head = NULL;
+               if (tx_ring->desc_head != NULL) {
+                       dma_free_coherent(&adapter->pdev->dev,
+                                         TX_DESC_RINGSIZE(tx_ring),
+                                         tx_ring->desc_head,
+                                         tx_ring->phys_addr);
+                       tx_ring->desc_head = NULL;
+               }
        }
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
@@ -671,40 +672,43 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
 }
 
 
-/* Get MAC address of a NIC partition */
-int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
 {
-       int err;
+       int err, i;
        struct qlcnic_cmd_args cmd;
+       u32 mac_low, mac_high;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = adapter->ahw->pci_func | BIT_8;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_MAC_ADDRESS;
-       cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+       cmd.req.arg[1] = adapter->ahw->pci_func | BIT_8;
+       err = qlcnic_issue_cmd(adapter, &cmd);
 
-       if (err == QLCNIC_RCODE_SUCCESS)
-               qlcnic_fetch_mac(cmd.rsp.arg1, cmd.rsp.arg2, 0, mac);
-       else {
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               mac_low = cmd.rsp.arg[1];
+               mac_high = cmd.rsp.arg[2];
+
+               for (i = 0; i < 2; i++)
+                       mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+               for (i = 2; i < 6; i++)
+                       mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+       } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get mac address%d\n", err);
                err = -EIO;
        }
-
+       qlcnic_free_mbx_args(&cmd);
        return err;
 }
 
 /* Get info of a NIC partition */
-int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
-                               struct qlcnic_info *npar_info, u8 func_id)
+int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter,
+                            struct qlcnic_info *npar_info, u8 func_id)
 {
        int     err;
        dma_addr_t nic_dma_t;
-       struct qlcnic_info_le *nic_info;
+       const struct qlcnic_info_le *nic_info;
        void *nic_info_addr;
        struct qlcnic_cmd_args cmd;
-       size_t  nic_size = sizeof(struct qlcnic_info_le);
+       size_t  nic_size = sizeof(struct qlcnic_info_le);
 
        nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
                                &nic_dma_t, GFP_KERNEL);
@@ -713,47 +717,39 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
        memset(nic_info_addr, 0, nic_size);
 
        nic_info = nic_info_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_NIC_INFO;
-       cmd.req.arg1 = MSD(nic_dma_t);
-       cmd.req.arg2 = LSD(nic_dma_t);
-       cmd.req.arg3 = (func_id << 16 | nic_size);
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
 
-       if (err == QLCNIC_RCODE_SUCCESS) {
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+       cmd.req.arg[1] = MSD(nic_dma_t);
+       cmd.req.arg[2] = LSD(nic_dma_t);
+       cmd.req.arg[3] = (func_id << 16 | nic_size);
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get nic info%d\n", err);
+               err = -EIO;
+       } else {
                npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
                npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
+               npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+               npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
                npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
                npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
                npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
                npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
-               npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
-               npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
                npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
                npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
-
-               dev_info(&adapter->pdev->dev,
-                       "phy port: %d switch_mode: %d,\n"
-                       "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
-                       "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
-                       npar_info->phys_port, npar_info->switch_mode,
-                       npar_info->max_tx_ques, npar_info->max_rx_ques,
-                       npar_info->min_tx_bw, npar_info->max_tx_bw,
-                       npar_info->max_mtu, npar_info->capabilities);
-       } else {
-               dev_err(&adapter->pdev->dev,
-                       "Failed to get nic info%d\n", err);
-               err = -EIO;
        }
 
        dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
-               nic_dma_t);
+                         nic_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
 /* Configure a NIC partition */
-int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
+int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter,
+                            struct qlcnic_info *nic)
 {
        int err = -EIO;
        dma_addr_t nic_dma_t;
@@ -784,13 +780,11 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
        nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
        nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_SET_NIC_INFO;
-       cmd.req.arg1 = MSD(nic_dma_t);
-       cmd.req.arg2 = LSD(nic_dma_t);
-       cmd.req.arg3 = ((nic->pci_func << 16) | nic_size);
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+       cmd.req.arg[1] = MSD(nic_dma_t);
+       cmd.req.arg[2] = LSD(nic_dma_t);
+       cmd.req.arg[3] = ((nic->pci_func << 16) | nic_size);
+       err = qlcnic_issue_cmd(adapter, &cmd);
 
        if (err != QLCNIC_RCODE_SUCCESS) {
                dev_err(&adapter->pdev->dev,
@@ -800,12 +794,14 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 
        dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
                nic_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
 /* Get PCI Info of a partition */
-int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
-                               struct qlcnic_pci_info *pci_info)
+int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
+                            struct qlcnic_pci_info *pci_info)
 {
        int err = 0, i;
        struct qlcnic_cmd_args cmd;
@@ -822,13 +818,11 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
        memset(pci_info_addr, 0, pci_size);
 
        npar = pci_info_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_PCI_INFO;
-       cmd.req.arg1 = MSD(pci_info_dma_t);
-       cmd.req.arg2 = LSD(pci_info_dma_t);
-       cmd.req.arg3 = pci_size;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+       cmd.req.arg[1] = MSD(pci_info_dma_t);
+       cmd.req.arg[2] = LSD(pci_info_dma_t);
+       cmd.req.arg[3] = pci_size;
+       err = qlcnic_issue_cmd(adapter, &cmd);
 
        adapter->ahw->act_pci_func = 0;
        if (err == QLCNIC_RCODE_SUCCESS) {
@@ -854,6 +848,8 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
 
        dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr,
                pci_info_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
@@ -872,21 +868,19 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
        arg1 = id | (enable_mirroring ? BIT_4 : 0);
        arg1 |= pci_func << 8;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_SET_PORTMIRRORING;
-       cmd.req.arg1 = arg1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORTMIRRORING);
+       cmd.req.arg[1] = arg1;
+       err = qlcnic_issue_cmd(adapter, &cmd);
 
-       if (err != QLCNIC_RCODE_SUCCESS) {
+       if (err != QLCNIC_RCODE_SUCCESS)
                dev_err(&adapter->pdev->dev,
                        "Failed to configure port mirroring%d on eswitch:%d\n",
                        pci_func, id);
-       } else {
+       else
                dev_info(&adapter->pdev->dev,
                        "Configured eSwitch %d for port mirroring:%d\n",
                        id, pci_func);
-       }
+       qlcnic_free_mbx_args(&cmd);
 
        return err;
 }
@@ -923,13 +917,11 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
        arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
        arg1 |= rx_tx << 15 | stats_size << 16;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
-       cmd.req.arg1 = arg1;
-       cmd.req.arg2 = MSD(stats_dma_t);
-       cmd.req.arg3 = LSD(stats_dma_t);
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+       cmd.req.arg[1] = arg1;
+       cmd.req.arg[2] = MSD(stats_dma_t);
+       cmd.req.arg[3] = LSD(stats_dma_t);
+       err = qlcnic_issue_cmd(adapter, &cmd);
 
        if (!err) {
                stats = stats_addr;
@@ -949,6 +941,8 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
 
        dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
                stats_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
@@ -963,6 +957,9 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
        void *stats_addr;
        int err;
 
+       if (mac_stats == NULL)
+               return -ENOMEM;
+
        stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
                        &stats_dma_t, GFP_KERNEL);
        if (!stats_addr) {
@@ -971,15 +968,11 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
                return -ENOMEM;
        }
        memset(stats_addr, 0, stats_size);
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_MAC_STATS;
-       cmd.req.arg1 = stats_size << 16;
-       cmd.req.arg2 = MSD(stats_dma_t);
-       cmd.req.arg3 = LSD(stats_dma_t);
-
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
-
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_MAC_STATS);
+       cmd.req.arg[1] = stats_size << 16;
+       cmd.req.arg[2] = MSD(stats_dma_t);
+       cmd.req.arg[3] = LSD(stats_dma_t);
+       err = qlcnic_issue_cmd(adapter, &cmd);
        if (!err) {
                stats = stats_addr;
                mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames);
@@ -1001,10 +994,16 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
                mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber);
                mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped);
                mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Get mac stats failed, err=%d.\n", __func__, err);
        }
 
        dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
                stats_dma_t);
+
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
@@ -1065,7 +1064,7 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
 int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
                const u8 port, const u8 rx_tx)
 {
-
+       int err;
        u32 arg1;
        struct qlcnic_cmd_args cmd;
 
@@ -1088,15 +1087,16 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
        arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
        arg1 |= BIT_14 | rx_tx << 15;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
-       cmd.req.arg1 = arg1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       return cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+       cmd.req.arg[1] = arg1;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 
 err_ret:
-       dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
-               "rx_ctx=%d\n", func_esw, port, rx_tx);
+       dev_err(&adapter->pdev->dev,
+               "Invalid args func_esw %d port %d rx_ctx %d\n",
+               func_esw, port, rx_tx);
        return -EIO;
 }
 
@@ -1109,22 +1109,21 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
        u8 pci_func;
        pci_func = (*arg1 >> 8);
 
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG;
-       cmd.req.arg1 = *arg1;
-       cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       *arg1 = cmd.rsp.arg1;
-       *arg2 = cmd.rsp.arg2;
-       err = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter,
+                             QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
+       cmd.req.arg[1] = *arg1;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       *arg1 = cmd.rsp.arg[1];
+       *arg2 = cmd.rsp.arg[2];
+       qlcnic_free_mbx_args(&cmd);
 
-       if (err == QLCNIC_RCODE_SUCCESS) {
+       if (err == QLCNIC_RCODE_SUCCESS)
                dev_info(&adapter->pdev->dev,
-                       "eSwitch port config for pci func %d\n", pci_func);
-       } else {
+                        "eSwitch port config for pci func %d\n", pci_func);
+       else
                dev_err(&adapter->pdev->dev,
                        "Failed to get eswitch port config for pci func %d\n",
                                                                pci_func);
-       }
        return err;
 }
 /* Configure eSwitch port
@@ -1189,20 +1188,18 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
                return err;
        }
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH;
-       cmd.req.arg1 = arg1;
-       cmd.req.arg2 = arg2;
-       qlcnic_issue_cmd(adapter, &cmd);
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_ESWITCH);
+       cmd.req.arg[1] = arg1;
+       cmd.req.arg[2] = arg2;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       qlcnic_free_mbx_args(&cmd);
 
-       err = cmd.rsp.cmd;
-       if (err != QLCNIC_RCODE_SUCCESS) {
+       if (err != QLCNIC_RCODE_SUCCESS)
                dev_err(&adapter->pdev->dev,
                        "Failed to configure eswitch pci func %d\n", pci_func);
-       } else {
+       else
                dev_info(&adapter->pdev->dev,
-                       "Configured eSwitch for pci func %d\n", pci_func);
-       }
+                        "Configured eSwitch for pci func %d\n", pci_func);
 
        return err;
 }
index 74b98110c5b45c6549d63c9ab76f36f040b9e340..f65fd7b6f9ae087d234bbeea2fcdf1f0a854d8ca 100644 (file)
@@ -22,42 +22,37 @@ struct qlcnic_stats {
 
 #define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
 #define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
+static const u32 qlcnic_fw_dump_level[] = {
+       0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
+};
 
 static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
-       {"xmit_called",
-               QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
-       {"xmit_finished",
-               QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
-       {"rx_dropped",
-               QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
-       {"tx_dropped",
-               QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
-       {"csummed",
-               QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
-       {"rx_pkts",
-               QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
-       {"lro_pkts",
-               QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
-       {"rx_bytes",
-               QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
-       {"tx_bytes",
-               QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
-       {"lrobytes",
-               QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
-       {"lso_frames",
-               QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
-       {"xmit_on",
-               QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
-       {"xmit_off",
-               QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
+       {"xmit_called", QLC_SIZEOF(stats.xmitcalled),
+               QLC_OFF(stats.xmitcalled)},
+       {"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
+               QLC_OFF(stats.xmitfinished)},
+       {"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
+       {"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
+       {"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
+       {"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
+       {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
+       {"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
+       {"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
+       {"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
+       {"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
+       {"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
+       {"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
        {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
-               QLC_OFF(stats.skb_alloc_failure)},
-       {"null rxbuf",
-               QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
+        QLC_OFF(stats.skb_alloc_failure)},
+       {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
        {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
                                         QLC_OFF(stats.rx_dma_map_error)},
        {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
                                         QLC_OFF(stats.tx_dma_map_error)},
+       {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
+                               QLC_OFF(stats.mac_filter_limit_overrun)},
+       {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
+        QLC_OFF(stats.spurious_intr)},
 
 };
 
@@ -78,7 +73,15 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
        "tx numbytes",
 };
 
-static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
+static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
+       "ctx_tx_bytes",
+       "ctx_tx_pkts",
+       "ctx_tx_errors",
+       "ctx_tx_dropped_pkts",
+       "ctx_tx_num_buffers",
+};
+
+static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
        "mac_tx_frames",
        "mac_tx_bytes",
        "mac_tx_mcast_pkts",
@@ -110,35 +113,70 @@ static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
        "mac_rx_length_large",
        "mac_rx_jabber",
        "mac_rx_dropped",
-       "mac_rx_crc_error",
+       "mac_crc_error",
        "mac_align_error",
 };
 
-#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
-#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)
-#define QLCNIC_DEVICE_STATS_LEN        ARRAY_SIZE(qlcnic_device_gstrings_stats)
-#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN
+#define QLCNIC_STATS_LEN       ARRAY_SIZE(qlcnic_gstrings_stats)
+static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
+       "ctx_rx_bytes",
+       "ctx_rx_pkts",
+       "ctx_lro_pkt_cnt",
+       "ctx_ip_csum_error",
+       "ctx_rx_pkts_wo_ctx",
+       "ctx_rx_pkts_dropped_wo_sts",
+       "ctx_rx_osized_pkts",
+       "ctx_rx_pkts_dropped_wo_rds",
+       "ctx_rx_unexpected_mcast_pkts",
+       "ctx_invalid_mac_address",
+       "ctx_rx_rds_ring_prim_attemoted",
+       "ctx_rx_rds_ring_prim_success",
+       "ctx_num_lro_flows_added",
+       "ctx_num_lro_flows_removed",
+       "ctx_num_lro_flows_active",
+       "ctx_pkts_dropped_unknown",
+};
 
 static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
        "Register_Test_on_offline",
        "Link_Test_on_offline",
        "Interrupt_Test_offline",
        "Internal_Loopback_offline",
-       "External_Loopback_offline"
+       "EEPROM_Test_offline"
 };
 
 #define QLCNIC_TEST_LEN        ARRAY_SIZE(qlcnic_gstrings_test)
 
+static inline int qlcnic_82xx_statistics(void)
+{
+       return QLCNIC_STATS_LEN + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+}
+
+static inline int qlcnic_83xx_statistics(void)
+{
+       return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
+              ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
+              ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+}
+
+static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)
+{
+       if (qlcnic_82xx_check(adapter))
+               return qlcnic_82xx_statistics();
+       else if (qlcnic_83xx_check(adapter))
+               return qlcnic_83xx_statistics();
+       else
+               return -1;
+}
+
 #define QLCNIC_RING_REGS_COUNT 20
 #define QLCNIC_RING_REGS_LEN   (QLCNIC_RING_REGS_COUNT * sizeof(u32))
 #define QLCNIC_MAX_EEPROM_LEN   1024
 
 static const u32 diag_registers[] = {
-       CRB_CMDPEG_STATE,
-       CRB_RCVPEG_STATE,
-       CRB_XG_STATE_P3P,
-       CRB_FW_CAPABILITIES_1,
-       ISR_INT_STATE_REG,
+       QLCNIC_CMDPEG_STATE,
+       QLCNIC_RCVPEG_STATE,
+       QLCNIC_FW_CAPABILITIES,
        QLCNIC_CRB_DRV_ACTIVE,
        QLCNIC_CRB_DEV_STATE,
        QLCNIC_CRB_DRV_STATE,
@@ -148,6 +186,13 @@ static const u32 diag_registers[] = {
        QLCNIC_PEG_ALIVE_COUNTER,
        QLCNIC_PEG_HALT_STATUS1,
        QLCNIC_PEG_HALT_STATUS2,
+       -1
+};
+
+
+static const u32 ext_diag_registers[] = {
+       CRB_XG_STATE_P3P,
+       ISR_INT_STATE_REG,
        QLCNIC_CRB_PEG_NET_0+0x3c,
        QLCNIC_CRB_PEG_NET_1+0x3c,
        QLCNIC_CRB_PEG_NET_2+0x3c,
@@ -156,12 +201,19 @@ static const u32 diag_registers[] = {
 };
 
 #define QLCNIC_MGMT_API_VERSION        2
-#define QLCNIC_DEV_INFO_SIZE   1
-#define QLCNIC_ETHTOOL_REGS_VER        2
+#define QLCNIC_ETHTOOL_REGS_VER        3
+
 static int qlcnic_get_regs_len(struct net_device *dev)
 {
-       return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
-                               QLCNIC_DEV_INFO_SIZE + 1;
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       u32 len;
+
+       if (qlcnic_83xx_check(adapter))
+               len = qlcnic_83xx_get_regs_len(adapter);
+       else
+               len = sizeof(ext_diag_registers) + sizeof(diag_registers);
+
+       return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
 }
 
 static int qlcnic_get_eeprom_len(struct net_device *dev)
@@ -174,10 +226,9 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 fw_major, fw_minor, fw_build;
-
-       fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
-       fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
-       fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+       fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+       fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+       fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
        snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
                "%d.%d.%d", fw_major, fw_minor, fw_build);
 
@@ -192,7 +243,10 @@ static int
 qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       u32 speed, reg;
        int check_sfp_module = 0;
+       u16 pcifn = ahw->pci_func;
 
        /* read which mode */
        if (adapter->ahw->port_type == QLCNIC_GBE) {
@@ -213,9 +267,12 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                ecmd->autoneg = adapter->ahw->link_autoneg;
 
        } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
-               u32 val;
+               u32 val = 0;
+               if (qlcnic_83xx_check(adapter))
+                       qlcnic_83xx_get_settings(adapter);
+               else
+                       val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
 
-               val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
                if (val == QLCNIC_PORT_MODE_802_3_AP) {
                        ecmd->supported = SUPPORTED_1000baseT_Full;
                        ecmd->advertising = ADVERTISED_1000baseT_Full;
@@ -225,6 +282,12 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                }
 
                if (netif_running(dev) && adapter->ahw->has_link_events) {
+                       if (qlcnic_82xx_check(adapter)) {
+                               reg = QLCRD32(adapter,
+                                             P3P_LINK_SPEED_REG(pcifn));
+                               speed = P3P_LINK_SPEED_VAL(pcifn, reg);
+                               ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+                       }
                        ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
                        ecmd->autoneg = adapter->ahw->link_autoneg;
                        ecmd->duplex = adapter->ahw->link_duplex;
@@ -294,6 +357,13 @@ skip:
                        ecmd->port = PORT_TP;
                }
                break;
+       case QLCNIC_BRDTYPE_83XX_10G:
+               ecmd->autoneg = AUTONEG_DISABLE;
+               ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
+               ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP);
+               ecmd->port = PORT_FIBRE;
+               check_sfp_module = netif_running(dev) && ahw->has_link_events;
+               break;
        default:
                dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
                        adapter->ahw->board_type);
@@ -321,16 +391,10 @@ skip:
        return 0;
 }
 
-static int
-qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,
+                                 struct ethtool_cmd *ecmd)
 {
-       u32 config = 0;
-       u32 ret = 0;
-       struct qlcnic_adapter *adapter = netdev_priv(dev);
-
-       if (adapter->ahw->port_type != QLCNIC_GBE)
-               return -EOPNOTSUPP;
-
+       u32 ret = 0, config = 0;
        /* read which mode */
        if (ecmd->duplex)
                config |= 0x1;
@@ -358,6 +422,24 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                return -EOPNOTSUPP;
        else if (ret)
                return -EIO;
+       return ret;
+}
+
+static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       u32 ret = 0;
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+       if (adapter->ahw->port_type != QLCNIC_GBE)
+               return -EOPNOTSUPP;
+
+       if (qlcnic_83xx_check(adapter))
+               ret = qlcnic_83xx_set_settings(adapter, ecmd);
+       else
+               ret = qlcnic_set_port_config(adapter, ecmd);
+
+       if (!ret)
+               return ret;
 
        adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
        adapter->ahw->link_duplex = ecmd->duplex;
@@ -370,6 +452,19 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        return dev->netdev_ops->ndo_open(dev);
 }
 
+static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
+                                    u32 *regs_buff)
+{
+       int i, j = 0;
+
+       for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
+               regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
+       j = 0;
+       while (ext_diag_registers[j] != -1)
+               regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
+       return i;
+}
+
 static void
 qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 {
@@ -377,17 +472,20 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
        struct qlcnic_host_sds_ring *sds_ring;
        u32 *regs_buff = p;
-       int ring, i = 0, j = 0;
+       int ring, i = 0;
 
        memset(p, 0, qlcnic_get_regs_len(dev));
+
        regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
                (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
 
        regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
        regs_buff[1] = QLCNIC_MGMT_API_VERSION;
 
-       for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
-               regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
+       if (qlcnic_82xx_check(adapter))
+               i = qlcnic_82xx_get_registers(adapter, regs_buff);
+       else
+               i = qlcnic_83xx_get_registers(adapter, regs_buff);
 
        if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
                return;
@@ -415,6 +513,10 @@ static u32 qlcnic_test_link(struct net_device *dev)
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 val;
 
+       if (qlcnic_83xx_check(adapter)) {
+               val = qlcnic_83xx_test_link(adapter);
+               return (val & 1) ? 0 : 1;
+       }
        val = QLCRD32(adapter, CRB_XG_STATE_P3P);
        val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
        return (val == XG_LINK_UP_P3P) ? 0 : 1;
@@ -426,8 +528,10 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        int offset;
-       int ret;
+       int ret = -1;
 
+       if (qlcnic_83xx_check(adapter))
+               return 0;
        if (eeprom->len == 0)
                return -EINVAL;
 
@@ -435,8 +539,9 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        ((adapter->pdev)->device << 16);
        offset = eeprom->offset;
 
-       ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
-                                               eeprom->len);
+       if (qlcnic_82xx_check(adapter))
+               ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
+                                                eeprom->len);
        if (ret < 0)
                return ret;
 
@@ -529,11 +634,11 @@ static int qlcnic_set_channels(struct net_device *dev,
            channel->tx_count != channel->max_tx)
                return -EINVAL;
 
-       err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
+       err = qlcnic_validate_max_rss(channel->max_rx, channel->rx_count);
        if (err)
                return err;
 
-       err = qlcnic_set_max_rss(adapter, channel->rx_count);
+       err = qlcnic_set_max_rss(adapter, channel->rx_count, 0);
        netdev_info(dev, "allocated 0x%x sds rings\n",
                                 adapter->max_sds_rings);
        return err;
@@ -547,6 +652,10 @@ qlcnic_get_pauseparam(struct net_device *netdev,
        int port = adapter->ahw->physical_port;
        __u32 val;
 
+       if (qlcnic_83xx_check(adapter)) {
+               qlcnic_83xx_get_pauseparam(adapter, pause);
+               return;
+       }
        if (adapter->ahw->port_type == QLCNIC_GBE) {
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
                        return;
@@ -592,6 +701,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
        int port = adapter->ahw->physical_port;
        __u32 val;
 
+       if (qlcnic_83xx_check(adapter))
+               return qlcnic_83xx_set_pauseparam(adapter, pause);
+
        /* read mode */
        if (adapter->ahw->port_type == QLCNIC_GBE) {
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
@@ -606,6 +718,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
 
                QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
                                val);
+               QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
                /* set autoneg */
                val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
                switch (port) {
@@ -668,6 +781,9 @@ static int qlcnic_reg_test(struct net_device *dev)
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 data_read;
 
+       if (qlcnic_83xx_check(adapter))
+               return qlcnic_83xx_reg_test(adapter);
+
        data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
        if ((data_read & 0xffff) != adapter->pdev->vendor)
                return 1;
@@ -675,16 +791,30 @@ static int qlcnic_reg_test(struct net_device *dev)
        return 0;
 }
 
+static int qlcnic_eeprom_test(struct net_device *dev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+       if (qlcnic_82xx_check(adapter))
+               return 0;
+
+       return qlcnic_83xx_flash_test(adapter);
+}
+
 static int qlcnic_get_sset_count(struct net_device *dev, int sset)
 {
+       int len;
+
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        switch (sset) {
        case ETH_SS_TEST:
                return QLCNIC_TEST_LEN;
        case ETH_SS_STATS:
-               if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
-                       return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
-               return QLCNIC_TOTAL_STATS_LEN;
+               len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
+               if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+                   qlcnic_83xx_check(adapter))
+                       return len;
+               return qlcnic_82xx_statistics();
        default:
                return -EOPNOTSUPP;
        }
@@ -705,20 +835,23 @@ static int qlcnic_irq_test(struct net_device *netdev)
                goto clear_it;
 
        adapter->ahw->diag_cnt = 0;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_INTRPT_TEST;
-       cmd.req.arg1 = adapter->ahw->pci_func;
-       qlcnic_issue_cmd(adapter, &cmd);
-       ret = cmd.rsp.cmd;
+       qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+
+       if (qlcnic_83xx_check(adapter)) {
+               ret = qlcnic_83xx_interrupt_test(adapter, &cmd);
+       } else {
+               cmd.req.arg[1] = adapter->ahw->pci_func;
+               ret = qlcnic_issue_cmd(adapter, &cmd);
+       }
 
        if (ret)
                goto done;
 
-       msleep(10);
-
+       usleep_range(1000, 12000);
        ret = !adapter->ahw->diag_cnt;
 
 done:
+       qlcnic_free_mbx_args(&cmd);
        qlcnic_diag_free_res(netdev, max_sds_rings);
 
 clear_it:
@@ -761,11 +894,10 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
                skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
                qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
                skb_put(skb, QLCNIC_ILB_PKT_SIZE);
-
                adapter->ahw->diag_cnt = 0;
                qlcnic_xmit_frame(skb, adapter->netdev);
-
                loop = 0;
+
                do {
                        msleep(1);
                        qlcnic_process_rcv_ring_diag(sds_ring);
@@ -776,18 +908,18 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
                dev_kfree_skb_any(skb);
 
                if (!adapter->ahw->diag_cnt)
-                       QLCDB(adapter, DRV,
-                       "LB Test: packet #%d was not received\n", i + 1);
+                       dev_warn(&adapter->pdev->dev,
+                                "LB Test: packet #%d was not received\n",
+                                i + 1);
                else
                        cnt++;
        }
        if (cnt != i) {
-               dev_warn(&adapter->pdev->dev, "LB Test failed\n");
-               if (mode != QLCNIC_ILB_MODE) {
+               dev_err(&adapter->pdev->dev,
+                       "LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
+               if (mode != QLCNIC_ILB_MODE)
                        dev_warn(&adapter->pdev->dev,
-                               "WARNING: Please make sure external"
-                               "loopback connector is plugged in\n");
-               }
+                                "WARNING: Please check loopback cable\n");
                return -1;
        }
        return 0;
@@ -798,20 +930,23 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int max_sds_rings = adapter->max_sds_rings;
        struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        int loop = 0;
        int ret;
 
-       if (!(adapter->ahw->capabilities &
-             QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
-               netdev_info(netdev, "Firmware is not loopback test capable\n");
+       if (qlcnic_83xx_check(adapter))
+               goto skip_cap;
+       if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
+               dev_info(&adapter->pdev->dev,
+                        "Firmware do not support loopback test\n");
                return -EOPNOTSUPP;
        }
-
-       QLCDB(adapter, DRV, "%s loopback test in progress\n",
-                  mode == QLCNIC_ILB_MODE ? "internal" : "external");
-       if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
-               netdev_warn(netdev, "Loopback test not supported for non "
-                               "privilege function\n");
+skip_cap:
+       dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
+                mode == QLCNIC_ILB_MODE ? "internal" : "external");
+       if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               dev_warn(&adapter->pdev->dev,
+                        "Loopback test not supported in nonprivileged mode\n");
                return 0;
        }
 
@@ -823,12 +958,14 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
                goto clear_it;
 
        sds_ring = &adapter->recv_ctx->sds_rings[0];
-
        ret = qlcnic_set_lb_mode(adapter, mode);
        if (ret)
                goto free_res;
 
-       adapter->ahw->diag_cnt = 0;
+       if (qlcnic_83xx_check(adapter))
+               goto skip_fw_msg;
+
+       ahw->diag_cnt = 0;
        do {
                msleep(500);
                qlcnic_process_rcv_ring_diag(sds_ring);
@@ -841,11 +978,23 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
                        ret = adapter->ahw->diag_cnt;
                        goto free_res;
                }
-       } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
-
+       } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
+skip_fw_msg:
+       if (qlcnic_83xx_check(adapter)) {
+               /* wait until firmware report link up before running traffic */
+               loop = 0;
+               do {
+                       msleep(500);
+                       if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+                               dev_info(&adapter->pdev->dev,
+                                        "No linkup event after LB req\n");
+                               ret = -QLCNIC_FW_NOT_RESPOND;
+                               goto free_res;
+                       }
+               } while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
+       }
        ret = qlcnic_do_lb_test(adapter, mode);
-
-       qlcnic_clear_lb_mode(adapter);
+       qlcnic_clear_lb_mode(adapter, mode);
 
  free_res:
        qlcnic_diag_free_res(netdev, max_sds_rings);
@@ -878,20 +1027,18 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
                data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
                if (data[3])
                        eth_test->flags |= ETH_TEST_FL_FAILED;
-               if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
-                       data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
-                       if (data[4])
-                               eth_test->flags |= ETH_TEST_FL_FAILED;
-                       eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
-               }
+
+               data[4] = qlcnic_eeprom_test(dev);
+               if (data[4])
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
        }
 }
 
 static void
-qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
-       int index, i, j;
+       int index, i, num_stats;
 
        switch (stringset) {
        case ETH_SS_TEST:
@@ -904,14 +1051,34 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
                               qlcnic_gstrings_stats[index].stat_string,
                               ETH_GSTRING_LEN);
                }
-               for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) {
-                       memcpy(data + index * ETH_GSTRING_LEN,
-                              qlcnic_mac_stats_strings[j],
-                              ETH_GSTRING_LEN);
+               if (qlcnic_83xx_check(adapter)) {
+                       num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                      qlcnic_83xx_tx_stats_strings[i],
+                                      ETH_GSTRING_LEN);
+                       num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                      qlcnic_83xx_mac_stats_strings[i],
+                                      ETH_GSTRING_LEN);
+                       num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                      qlcnic_83xx_rx_stats_strings[i],
+                                      ETH_GSTRING_LEN);
+                       return;
+               } else {
+                       num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                      qlcnic_83xx_mac_stats_strings[i],
+                                      ETH_GSTRING_LEN);
                }
                if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
                        return;
-               for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
+               num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
+               for (i = 0; i < num_stats; index++, i++) {
                        memcpy(data + index * ETH_GSTRING_LEN,
                               qlcnic_device_gstrings_stats[i],
                               ETH_GSTRING_LEN);
@@ -920,89 +1087,84 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
 }
 
 static void
-qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
+qlcnic_fill_stats(u64 *data, void *stats, int type)
 {
-       int ind = *index;
-
        if (type == QLCNIC_MAC_STATS) {
                struct qlcnic_mac_statistics *mac_stats =
                                        (struct qlcnic_mac_statistics *)stats;
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
        } else if (type == QLCNIC_ESW_STATS) {
                struct __qlcnic_esw_statistics *esw_stats =
                                (struct __qlcnic_esw_statistics *)stats;
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->errors);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
        }
-
-       *index = ind;
 }
 
-static void
-qlcnic_get_ethtool_stats(struct net_device *dev,
-                            struct ethtool_stats *stats, u64 * data)
+static void qlcnic_get_ethtool_stats(struct net_device *dev,
+                                    struct ethtool_stats *stats, u64 *data)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        struct qlcnic_esw_statistics port_stats;
        struct qlcnic_mac_statistics mac_stats;
-       int index, ret;
-
-       for (index = 0; index < QLCNIC_STATS_LEN; index++) {
-               char *p =
-                   (char *)adapter +
-                   qlcnic_gstrings_stats[index].stat_offset;
-               data[index] =
-                   (qlcnic_gstrings_stats[index].sizeof_stat ==
-                    sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
+       int index, ret, length, size;
+       char *p;
+
+       memset(data, 0, stats->n_stats * sizeof(u64));
+       length = QLCNIC_STATS_LEN;
+       for (index = 0; index < length; index++) {
+               p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset;
+               size = qlcnic_gstrings_stats[index].sizeof_stat;
+               *data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
        }
 
-       /* Retrieve MAC statistics from firmware */
-       memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
-       qlcnic_get_mac_stats(adapter, &mac_stats);
-       qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS);
+       if (qlcnic_83xx_check(adapter)) {
+               if (adapter->ahw->linkup)
+                       qlcnic_83xx_get_stats(adapter, data);
+               return;
+       } else {
+               /* Retrieve MAC statistics from firmware */
+               memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
+               qlcnic_get_mac_stats(adapter, &mac_stats);
+               qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
+       }
 
        if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
                return;
@@ -1013,14 +1175,13 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
        if (ret)
                return;
 
-       qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);
-
+       qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
        ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
                        QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
        if (ret)
                return;
 
-       qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
+       qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
 }
 
 static int qlcnic_set_led(struct net_device *dev,
@@ -1030,6 +1191,8 @@ static int qlcnic_set_led(struct net_device *dev,
        int max_sds_rings = adapter->max_sds_rings;
        int err = -EIO, active = 1;
 
+       if (qlcnic_83xx_check(adapter))
+               return -EOPNOTSUPP;
        if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
                netdev_warn(dev, "LED test not supported for non "
                                "privilege function\n");
@@ -1096,6 +1259,8 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
 
+       if (qlcnic_83xx_check(adapter))
+               return;
        wol->supported = 0;
        wol->wolopts = 0;
 
@@ -1114,8 +1279,10 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
 
-       if (wol->wolopts & ~WAKE_MAGIC)
+       if (qlcnic_83xx_check(adapter))
                return -EOPNOTSUPP;
+       if (wol->wolopts & ~WAKE_MAGIC)
+               return -EINVAL;
 
        wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
        if (!(wol_cfg & (1 << adapter->portnum)))
@@ -1307,7 +1474,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
                        return 0;
                }
                netdev_info(netdev, "Forcing a FW dump\n");
-               qlcnic_dev_request_reset(adapter);
+               qlcnic_dev_request_reset(adapter, val->flag);
                break;
        case QLCNIC_DISABLE_FW_DUMP:
                if (fw_dump->enable && fw_dump->tmpl_hdr) {
@@ -1327,7 +1494,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
                return 0;
        case QLCNIC_FORCE_FW_RESET:
                netdev_info(netdev, "Forcing a FW reset\n");
-               qlcnic_dev_request_reset(adapter);
+               qlcnic_dev_request_reset(adapter, val->flag);
                adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
                return 0;
        case QLCNIC_SET_QUIESCENT:
@@ -1341,8 +1508,8 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
                        netdev_err(netdev, "FW dump not supported\n");
                        return -ENOTSUPP;
                }
-               for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
-                       if (val->flag == FW_DUMP_LEVELS[i]) {
+               for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
+                       if (val->flag == qlcnic_fw_dump_level[i]) {
                                fw_dump->tmpl_hdr->drv_cap_mask =
                                                        val->flag;
                                netdev_info(netdev, "Driver mask changed to: 0x%x\n",
@@ -1386,10 +1553,3 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
        .get_dump_data = qlcnic_get_dump_data,
        .set_dump = qlcnic_set_dump,
 };
-
-const struct ethtool_ops qlcnic_ethtool_failed_ops = {
-       .get_settings = qlcnic_get_settings,
-       .get_drvinfo = qlcnic_get_drvinfo,
-       .set_msglevel = qlcnic_set_msglevel,
-       .get_msglevel = qlcnic_get_msglevel,
-};
index 49cc1ac4f0573b446a7a8c1228cf09760fa3f266..74f771122985bf4148b1d4aeca78974349917186 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+#include "qlcnic_hw.h"
+
 /*
  * The basic unit of access when reading/writing control registers.
  */
@@ -387,9 +389,6 @@ enum {
 #define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014)
 #define QLCNIC_ROMUSB_ROM_RDATA                (ROMUSB_ROM + 0x0018)
 
-/* Lock IDs for ROM lock */
-#define ROM_LOCK_DRIVER        0x0d417340
-
 /******************************************************************************
 *
 *    Definitions specific to M25P flash
@@ -449,13 +448,10 @@ enum {
 #define ISR_INT_TARGET_STATUS_F7   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
 #define ISR_INT_TARGET_MASK_F7     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
 
-#define QLCNIC_PCI_MN_2M       (0)
-#define QLCNIC_PCI_MS_2M       (0x80000)
 #define QLCNIC_PCI_OCM0_2M     (0x000c0000UL)
 #define QLCNIC_PCI_CRBSPACE    (0x06000000UL)
 #define QLCNIC_PCI_CAMQM       (0x04800000UL)
 #define QLCNIC_PCI_CAMQM_END   (0x04800800UL)
-#define QLCNIC_PCI_2MB_SIZE    (0x00200000UL)
 #define QLCNIC_PCI_CAMQM_2M_BASE       (0x000ff800UL)
 
 #define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM)
@@ -491,7 +487,7 @@ enum {
 #define QLCNIC_NIU_GB_MAC_CONFIG_1(I)          \
                (QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000)
 
-
+#define MAX_CTL_CHECK  1000
 #define TEST_AGT_CTRL  (0x00)
 
 #define TA_CTL_START   BIT_0
@@ -499,44 +495,6 @@ enum {
 #define TA_CTL_WRITE   BIT_2
 #define TA_CTL_BUSY    BIT_3
 
-/*
- *   Register offsets for MN
- */
-#define MIU_TEST_AGT_BASE              (0x90)
-
-#define MIU_TEST_AGT_ADDR_LO           (0x04)
-#define MIU_TEST_AGT_ADDR_HI           (0x08)
-#define MIU_TEST_AGT_WRDATA_LO         (0x10)
-#define MIU_TEST_AGT_WRDATA_HI         (0x14)
-#define MIU_TEST_AGT_WRDATA_UPPER_LO   (0x20)
-#define MIU_TEST_AGT_WRDATA_UPPER_HI   (0x24)
-#define MIU_TEST_AGT_WRDATA(i)         (0x10+(0x10*((i)>>1))+(4*((i)&1)))
-#define MIU_TEST_AGT_RDDATA_LO         (0x18)
-#define MIU_TEST_AGT_RDDATA_HI         (0x1c)
-#define MIU_TEST_AGT_RDDATA_UPPER_LO   (0x28)
-#define MIU_TEST_AGT_RDDATA_UPPER_HI   (0x2c)
-#define MIU_TEST_AGT_RDDATA(i)         (0x18+(0x10*((i)>>1))+(4*((i)&1)))
-
-#define MIU_TEST_AGT_ADDR_MASK         0xfffffff8
-#define MIU_TEST_AGT_UPPER_ADDR(off)   (0)
-
-/*
- *   Register offsets for MS
- */
-#define SIU_TEST_AGT_BASE              (0x60)
-
-#define SIU_TEST_AGT_ADDR_LO           (0x04)
-#define SIU_TEST_AGT_ADDR_HI           (0x18)
-#define SIU_TEST_AGT_WRDATA_LO         (0x08)
-#define SIU_TEST_AGT_WRDATA_HI         (0x0c)
-#define SIU_TEST_AGT_WRDATA(i)         (0x08+(4*(i)))
-#define SIU_TEST_AGT_RDDATA_LO         (0x10)
-#define SIU_TEST_AGT_RDDATA_HI         (0x14)
-#define SIU_TEST_AGT_RDDATA(i)         (0x10+(4*(i)))
-
-#define SIU_TEST_AGT_ADDR_MASK         0x3ffff8
-#define SIU_TEST_AGT_UPPER_ADDR(off)   ((off)>>22)
-
 /* XG Link status */
 #define XG_LINK_UP     0x10
 #define XG_LINK_DOWN   0x20
@@ -556,9 +514,6 @@ enum {
 
 #define QLCNIC_CAM_RAM_BASE    (QLCNIC_CRB_CAM + 0x02000)
 #define QLCNIC_CAM_RAM(reg)    (QLCNIC_CAM_RAM_BASE + (reg))
-#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150))
-#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154))
-#define QLCNIC_FW_VERSION_SUB  (QLCNIC_CAM_RAM(0x158))
 #define QLCNIC_ROM_LOCK_ID     (QLCNIC_CAM_RAM(0x100))
 #define QLCNIC_PHY_LOCK_ID     (QLCNIC_CAM_RAM(0x120))
 #define QLCNIC_CRB_WIN_LOCK_ID (QLCNIC_CAM_RAM(0x124))
@@ -568,28 +523,17 @@ enum {
 #define QLCNIC_REG(X)          (NIC_CRB_BASE+(X))
 #define QLCNIC_REG_2(X)        (NIC_CRB_BASE_2+(X))
 
+#define QLCNIC_CDRP_MAX_ARGS   4
+#define QLCNIC_CDRP_ARG(i)     (QLCNIC_REG(0x18 + ((i) * 4)))
+
 #define QLCNIC_CDRP_CRB_OFFSET         (QLCNIC_REG(0x18))
-#define QLCNIC_ARG1_CRB_OFFSET         (QLCNIC_REG(0x1c))
-#define QLCNIC_ARG2_CRB_OFFSET         (QLCNIC_REG(0x20))
-#define QLCNIC_ARG3_CRB_OFFSET         (QLCNIC_REG(0x24))
 #define QLCNIC_SIGN_CRB_OFFSET         (QLCNIC_REG(0x28))
 
-#define CRB_CMDPEG_STATE               (QLCNIC_REG(0x50))
-#define CRB_RCVPEG_STATE               (QLCNIC_REG(0x13c))
-
 #define CRB_XG_STATE_P3P               (QLCNIC_REG(0x98))
 #define CRB_PF_LINK_SPEED_1            (QLCNIC_REG(0xe8))
-#define CRB_PF_LINK_SPEED_2            (QLCNIC_REG(0xec))
-
-#define CRB_TEMP_STATE                 (QLCNIC_REG(0x1b4))
-
-#define CRB_V2P_0                      (QLCNIC_REG(0x290))
-#define CRB_V2P(port)                  (CRB_V2P_0+((port)*4))
 #define CRB_DRIVER_VERSION             (QLCNIC_REG(0x2a0))
 
-#define CRB_FW_CAPABILITIES_1          (QLCNIC_CAM_RAM(0x128))
 #define CRB_FW_CAPABILITIES_2          (QLCNIC_CAM_RAM(0x12c))
-#define CRB_MAC_BLOCK_START            (QLCNIC_CAM_RAM(0x1c0))
 
 /*
  * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
@@ -616,11 +560,6 @@ enum {
 /* Lock IDs for PHY lock */
 #define PHY_LOCK_DRIVER                0x44524956
 
-/* Used for PS PCI Memory access */
-#define PCIX_PS_OP_ADDR_LO     (0x10000)
-/*   via CRB  (PS side only)     */
-#define PCIX_PS_OP_ADDR_HI     (0x10004)
-
 #define PCIX_INT_VECTOR        (0x10100)
 #define PCIX_INT_MASK          (0x10104)
 
@@ -682,17 +621,6 @@ enum {
 #define QLCNIC_PEG_TUNE_CAPABILITY     (QLCNIC_CAM_RAM(0x02c))
 
 #define QLCNIC_DMA_WATCHDOG_CTRL       (QLCNIC_CAM_RAM(0x14))
-#define QLCNIC_PEG_ALIVE_COUNTER       (QLCNIC_CAM_RAM(0xb0))
-#define QLCNIC_PEG_HALT_STATUS1        (QLCNIC_CAM_RAM(0xa8))
-#define QLCNIC_PEG_HALT_STATUS2        (QLCNIC_CAM_RAM(0xac))
-#define QLCNIC_CRB_DRV_ACTIVE  (QLCNIC_CAM_RAM(0x138))
-#define QLCNIC_CRB_DEV_STATE           (QLCNIC_CAM_RAM(0x140))
-
-#define QLCNIC_CRB_DRV_STATE           (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH         (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO  (QLCNIC_CAM_RAM(0x14c))
-#define QLCNIC_CRB_DRV_IDC_VER         (QLCNIC_CAM_RAM(0x174))
-#define QLCNIC_CRB_DEV_NPAR_STATE      (QLCNIC_CAM_RAM(0x19c))
 #define QLCNIC_ROM_DEV_INIT_TIMEOUT    (0x3e885c)
 #define QLCNIC_ROM_DRV_RESET_TIMEOUT   (0x3e8860)
 
@@ -711,7 +639,6 @@ enum {
 #define QLCNIC_DEV_NPAR_OPER           1 /* NPAR Operational */
 #define QLCNIC_DEV_NPAR_OPER_TIMEO     30 /* Operational time out */
 
-#define QLC_DEV_CHECK_ACTIVE(VAL, FN)          ((VAL) & (1 << (FN * 4)))
 #define QLC_DEV_SET_REF_CNT(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_CLR_REF_CNT(VAL, FN)           ((VAL) &= ~(1 << (FN * 4)))
 #define QLC_DEV_SET_RST_RDY(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
@@ -744,6 +671,9 @@ enum {
 #define QLCNIC_HEARTBEAT_PERIOD_MSECS  200
 #define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT     45
 
+#define QLCNIC_MAX_MC_COUNT            38
+#define QLCNIC_WATCHDOG_TIMEOUTVALUE   5
+
 #define        ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
 #define ISR_LEGACY_INT_TRIGGERED(VAL)  (((VAL) & 0x300) == 0x200)
 
@@ -766,26 +696,13 @@ struct qlcnic_legacy_intr_set {
        u32     pci_int_reg;
 };
 
-#define QLCNIC_FW_API          0x1b216c
-#define QLCNIC_DRV_OP_MODE     0x1b2170
 #define QLCNIC_MSIX_BASE       0x132110
 #define QLCNIC_MAX_PCI_FUNC    8
 #define QLCNIC_MAX_VLAN_FILTERS        64
 
-/* FW dump defines */
-#define MIU_TEST_CTR           0x41000090
-#define MIU_TEST_ADDR_LO       0x41000094
-#define MIU_TEST_ADDR_HI       0x41000098
 #define FLASH_ROM_WINDOW       0x42110030
 #define FLASH_ROM_DATA         0x42150000
 
-
-static const u32 FW_DUMP_LEVELS[] = {
-       0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
-
-static const u32 MIU_TEST_READ_DATA[] = {
-       0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
-
 #define QLCNIC_FW_DUMP_REG1    0x00130060
 #define QLCNIC_FW_DUMP_REG2    0x001e0000
 #define QLCNIC_FLASH_SEM2_LK   0x0013C010
@@ -796,7 +713,8 @@ static const u32 MIU_TEST_READ_DATA[] = {
 enum {
        QLCNIC_MGMT_FUNC        = 0,
        QLCNIC_PRIV_FUNC        = 1,
-       QLCNIC_NON_PRIV_FUNC    = 2
+       QLCNIC_NON_PRIV_FUNC    = 2,
+       QLCNIC_UNKNOWN_FUNC_MODE = 3
 };
 
 enum {
@@ -1013,6 +931,8 @@ enum {
 #define QLCNIC_NIU_PROMISC_MODE                1
 #define QLCNIC_NIU_ALLMULTI_MODE       2
 
+#define QLCNIC_PCIE_SEM_TIMEOUT        10000
+
 struct crb_128M_2M_sub_block_map {
        unsigned valid;
        unsigned start_128M;
index 7a6d5ebe4e0fead543542fbb2b9ecf1b5cb71d4d..6c6ecfc152b8b27fb6283a1b47e22152b9ea72b9 100644 (file)
@@ -344,21 +344,26 @@ qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
        QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
 }
 
-static int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
+int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
 {
        u32 data;
 
        if (qlcnic_82xx_check(adapter))
                qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
-       else
-               return -EIO;
+       else {
+               data = qlcnic_83xx_rd_reg_indirect(adapter, addr);
+               if (data == -EIO)
+                       return -EIO;
+       }
        return data;
 }
 
-static void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
+void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
 {
        if (qlcnic_82xx_check(adapter))
                qlcnic_write_window_reg(addr, adapter->ahw->pci_base0, data);
+       else
+               qlcnic_83xx_wrt_reg_indirect(adapter, addr, data);
 }
 
 static int
@@ -417,9 +422,8 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-static int
-qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
-                               __le16 vlan_id, unsigned op)
+int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+                                  __le16 vlan_id, u8 op)
 {
        struct qlcnic_nic_req req;
        struct qlcnic_mac_req *mac_req;
@@ -442,7 +446,29 @@ qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
        return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
 }
 
-static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
+int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
+{
+       struct list_head *head;
+       struct qlcnic_mac_list_s *cur;
+       int err = -EINVAL;
+
+       /* Delete MAC from the existing list */
+       list_for_each(head, &adapter->mac_list) {
+               cur = list_entry(head, struct qlcnic_mac_list_s, list);
+               if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) {
+                       err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
+                                                       0, QLCNIC_MAC_DEL);
+                       if (err)
+                               return err;
+                       list_del(&cur->list);
+                       kfree(cur);
+                       return err;
+               }
+       }
+       return err;
+}
+
+int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
 {
        struct list_head *head;
        struct qlcnic_mac_list_s *cur;
@@ -506,17 +532,17 @@ void qlcnic_set_multi(struct net_device *netdev)
        }
 
 send_fw_cmd:
-       if (mode == VPORT_MISS_MODE_ACCEPT_ALL) {
+       if (mode == VPORT_MISS_MODE_ACCEPT_ALL && !adapter->fdb_mac_learn) {
                qlcnic_alloc_lb_filters_mem(adapter);
-               adapter->mac_learn = 1;
+               adapter->drv_mac_learn = true;
        } else {
-               adapter->mac_learn = 0;
+               adapter->drv_mac_learn = false;
        }
 
        qlcnic_nic_set_promisc(adapter, mode);
 }
 
-int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
 {
        struct qlcnic_nic_req req;
        u64 word;
@@ -554,19 +580,20 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
        struct qlcnic_filter *tmp_fil;
        struct hlist_node *tmp_hnode, *n;
        struct hlist_head *head;
-       int i;
+       int i, time;
+       u8 cmd;
 
-       for (i = 0; i < adapter->fhash.fmax; i++) {
+       for (i = 0; i < adapter->fhash.fbucket_size; i++) {
                head = &(adapter->fhash.fhead[i]);
-
-               hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
-               {
-                       if (jiffies >
-                               (QLCNIC_FILTER_AGE * HZ + tmp_fil->ftime)) {
+               hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+                       cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+                                                 QLCNIC_MAC_DEL;
+                       time = tmp_fil->ftime;
+                       if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) {
                                qlcnic_sre_macaddr_change(adapter,
-                                       tmp_fil->faddr, tmp_fil->vlan_id,
-                                       tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
-                                       QLCNIC_MAC_DEL);
+                                                         tmp_fil->faddr,
+                                                         tmp_fil->vlan_id,
+                                                         cmd);
                                spin_lock_bh(&adapter->mac_learn_lock);
                                adapter->fhash.fnum--;
                                hlist_del(&tmp_fil->fnode);
@@ -583,14 +610,17 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
        struct hlist_node *tmp_hnode, *n;
        struct hlist_head *head;
        int i;
+       u8 cmd;
 
-       for (i = 0; i < adapter->fhash.fmax; i++) {
+       for (i = 0; i < adapter->fhash.fbucket_size; i++) {
                head = &(adapter->fhash.fhead[i]);
-
                hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
-                       qlcnic_sre_macaddr_change(adapter, tmp_fil->faddr,
-                               tmp_fil->vlan_id, tmp_fil->vlan_id ?
-                               QLCNIC_MAC_VLAN_DEL :  QLCNIC_MAC_DEL);
+                       cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+                                                 QLCNIC_MAC_DEL;
+                       qlcnic_sre_macaddr_change(adapter,
+                                                 tmp_fil->faddr,
+                                                 tmp_fil->vlan_id,
+                                                 cmd);
                        spin_lock_bh(&adapter->mac_learn_lock);
                        adapter->fhash.fnum--;
                        hlist_del(&tmp_fil->fnode);
@@ -620,12 +650,13 @@ static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u8 flag)
        return rv;
 }
 
-int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 {
        if (qlcnic_set_fw_loopback(adapter, mode))
                return -EIO;
 
-       if (qlcnic_nic_set_promisc(adapter, VPORT_MISS_MODE_ACCEPT_ALL)) {
+       if (qlcnic_nic_set_promisc(adapter,
+                                  VPORT_MISS_MODE_ACCEPT_ALL)) {
                qlcnic_set_fw_loopback(adapter, 0);
                return -EIO;
        }
@@ -634,11 +665,11 @@ int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
        return 0;
 }
 
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 {
-       int mode = VPORT_MISS_MODE_DROP;
        struct net_device *netdev = adapter->netdev;
 
+       mode = VPORT_MISS_MODE_DROP;
        qlcnic_set_fw_loopback(adapter, 0);
 
        if (netdev->flags & IFF_PROMISC)
@@ -648,12 +679,13 @@ void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
 
        qlcnic_nic_set_promisc(adapter, mode);
        msleep(1000);
+       return 0;
 }
 
 /*
  * Send the interrupt coalescing parameter set by ethtool to the card.
  */
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_nic_req req;
        int rv;
@@ -675,10 +707,14 @@ int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
        if (rv != 0)
                dev_err(&adapter->netdev->dev,
                        "Could not send interrupt coalescing parameters\n");
-       return rv;
 }
 
-int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
+#define QLCNIC_ENABLE_IPV4_LRO         1
+#define QLCNIC_ENABLE_IPV6_LRO         2
+#define QLCNIC_NO_DEST_IPV4_CHECK      (1 << 8)
+#define QLCNIC_NO_DEST_IPV6_CHECK      (2 << 8)
+
+int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
 {
        struct qlcnic_nic_req req;
        u64 word;
@@ -694,7 +730,15 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
        word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16);
        req.req_hdr = cpu_to_le64(word);
 
-       req.words[0] = cpu_to_le64(enable);
+       word = 0;
+       if (enable) {
+               word = QLCNIC_ENABLE_IPV4_LRO | QLCNIC_NO_DEST_IPV4_CHECK;
+               if (adapter->ahw->capabilities2 & QLCNIC_FW_CAP2_HW_LRO_IPV6)
+                       word |= QLCNIC_ENABLE_IPV6_LRO |
+                               QLCNIC_NO_DEST_IPV6_CHECK;
+       }
+
+       req.words[0] = cpu_to_le64(word);
 
        rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
        if (rv != 0)
@@ -734,9 +778,12 @@ int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
 }
 
 
-#define RSS_HASHTYPE_IP_TCP    0x3
+#define QLCNIC_RSS_HASHTYPE_IP_TCP     0x3
+#define QLCNIC_ENABLE_TYPE_C_RSS       BIT_10
+#define QLCNIC_RSS_FEATURE_FLAG        (1ULL << 63)
+#define QLCNIC_RSS_IND_TABLE_MASK      0x7ULL
 
-int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int enable)
 {
        struct qlcnic_nic_req req;
        u64 word;
@@ -761,13 +808,19 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
         *      7-6: hash_type_ipv6
         *        8: enable
         *        9: use indirection table
-        *    47-10: reserved
-        *    63-48: indirection table mask
+        *       10: type-c rss
+        *       11: udp rss
+        *    47-12: reserved
+        *    62-48: indirection table mask
+        *       63: feature flag
         */
-       word =  ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
-               ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+       word =  ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+               ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
                ((u64)(enable & 0x1) << 8) |
-               ((0x7ULL) << 48);
+               ((u64)QLCNIC_RSS_IND_TABLE_MASK << 48) |
+               (u64)QLCNIC_ENABLE_TYPE_C_RSS |
+               (u64)QLCNIC_RSS_FEATURE_FLAG;
+
        req.words[0] = cpu_to_le64(word);
        for (i = 0; i < 5; i++)
                req.words[i+1] = cpu_to_le64(key[i]);
@@ -779,7 +832,8 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
        return rv;
 }
 
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
+void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
+                              __be32 ip, int cmd)
 {
        struct qlcnic_nic_req req;
        struct qlcnic_ipaddr *ipa;
@@ -801,23 +855,19 @@ int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
                dev_err(&adapter->netdev->dev,
                                "could not notify %s IP 0x%x reuqest\n",
                                (cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
-
-       return rv;
 }
 
-int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable)
 {
        struct qlcnic_nic_req req;
        u64 word;
        int rv;
-
        memset(&req, 0, sizeof(struct qlcnic_nic_req));
        req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
 
        word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
        req.req_hdr = cpu_to_le64(word);
        req.words[0] = cpu_to_le64(enable | (enable << 8));
-
        rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
        if (rv != 0)
                dev_err(&adapter->netdev->dev,
@@ -903,7 +953,7 @@ int qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
        if (!(changed & NETIF_F_LRO))
                return 0;
 
-       netdev->features = features ^ NETIF_F_LRO;
+       netdev->features ^= NETIF_F_LRO;
 
        if (qlcnic_config_hw_lro(adapter, hw_lro))
                return -EIO;
@@ -981,8 +1031,8 @@ qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
        return 0;
 }
 
-int
-qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
+                              u32 data)
 {
        unsigned long flags;
        int rv;
@@ -1013,7 +1063,7 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
        return -EIO;
 }
 
-int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
 {
        unsigned long flags;
        int rv;
@@ -1042,7 +1092,6 @@ int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
        return -1;
 }
 
-
 void __iomem *qlcnic_get_ioaddr(struct qlcnic_hardware_context *ahw,
                                u32 offset)
 {
@@ -1268,7 +1317,7 @@ int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
        return ret;
 }
 
-int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
 {
        int offset, board_type, magic;
        struct pci_dev *pdev = adapter->pdev;
@@ -1341,7 +1390,7 @@ qlcnic_wol_supported(struct qlcnic_adapter *adapter)
        return 0;
 }
 
-int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
 {
        struct qlcnic_nic_req   req;
        int rv;
@@ -1353,7 +1402,7 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
        word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
        req.req_hdr = cpu_to_le64(word);
 
-       req.words[0] = cpu_to_le64((u64)rate << 32);
+       req.words[0] = cpu_to_le64(((u64)rate << 32) | adapter->portnum);
        req.words[1] = cpu_to_le64(state);
 
        rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
@@ -1362,3 +1411,56 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
 
        return rv;
 }
+
+void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
+{
+       void __iomem *msix_base_addr;
+       u32 func;
+       u32 msix_base;
+
+       pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+       msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
+       msix_base = readl(msix_base_addr);
+       func = (func - msix_base) / QLCNIC_MSIX_TBL_PGSIZE;
+       adapter->ahw->pci_func = func;
+}
+
+void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
+                         loff_t offset, size_t size)
+{
+       u32 data;
+       u64 qmdata;
+
+       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+               qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
+               memcpy(buf, &qmdata, size);
+       } else {
+               data = QLCRD32(adapter, offset);
+               memcpy(buf, &data, size);
+       }
+}
+
+void qlcnic_82xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
+                          loff_t offset, size_t size)
+{
+       u32 data;
+       u64 qmdata;
+
+       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+               memcpy(&qmdata, buf, size);
+               qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
+       } else {
+               memcpy(&data, buf, size);
+               QLCWR32(adapter, offset, data);
+       }
+}
+
+int qlcnic_82xx_api_lock(struct qlcnic_adapter *adapter)
+{
+       return qlcnic_pcie_sem_lock(adapter, 5, 0);
+}
+
+void qlcnic_82xx_api_unlock(struct qlcnic_adapter *adapter)
+{
+       qlcnic_pcie_sem_unlock(adapter, 5);
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
new file mode 100644 (file)
index 0000000..9673e2b
--- /dev/null
@@ -0,0 +1,186 @@
+#ifndef __QLCNIC_HW_H
+#define __QLCNIC_HW_H
+
+/* Common registers in 83xx and 82xx */
+enum qlcnic_regs {
+       QLCNIC_PEG_HALT_STATUS1 = 0,
+       QLCNIC_PEG_HALT_STATUS2,
+       QLCNIC_PEG_ALIVE_COUNTER,
+       QLCNIC_FLASH_LOCK_OWNER,
+       QLCNIC_FW_CAPABILITIES,
+       QLCNIC_CRB_DRV_ACTIVE,
+       QLCNIC_CRB_DEV_STATE,
+       QLCNIC_CRB_DRV_STATE,
+       QLCNIC_CRB_DRV_SCRATCH,
+       QLCNIC_CRB_DEV_PARTITION_INFO,
+       QLCNIC_CRB_DRV_IDC_VER,
+       QLCNIC_FW_VERSION_MAJOR,
+       QLCNIC_FW_VERSION_MINOR,
+       QLCNIC_FW_VERSION_SUB,
+       QLCNIC_CRB_DEV_NPAR_STATE,
+       QLCNIC_FW_IMG_VALID,
+       QLCNIC_CMDPEG_STATE,
+       QLCNIC_RCVPEG_STATE,
+       QLCNIC_ASIC_TEMP,
+       QLCNIC_FW_API,
+       QLCNIC_DRV_OP_MODE,
+       QLCNIC_FLASH_LOCK,
+       QLCNIC_FLASH_UNLOCK,
+};
+
+/* Read from an address offset from BAR0, existing registers */
+#define QLC_SHARED_REG_RD32(a, addr)                   \
+       readl(((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+
+/* Write to an address offset from BAR0, existing registers */
+#define QLC_SHARED_REG_WR32(a, addr, value)            \
+       writel(value, ((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+
+/* Read from a direct address offset from BAR0, additional registers */
+#define QLCRDX(ahw, addr)      \
+       readl(((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr]))
+
+/* Write to a direct address offset from BAR0, additional registers */
+#define QLCWRX(ahw, addr, value)       \
+       writel(value, (((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr])))
+
+#define QLCNIC_CMD_CONFIGURE_IP_ADDR           0x1
+#define QLCNIC_CMD_CONFIG_INTRPT               0x2
+#define QLCNIC_CMD_CREATE_RX_CTX               0x7
+#define QLCNIC_CMD_DESTROY_RX_CTX              0x8
+#define QLCNIC_CMD_CREATE_TX_CTX               0x9
+#define QLCNIC_CMD_DESTROY_TX_CTX              0xa
+#define QLCNIC_CMD_CONFIGURE_LRO               0xC
+#define QLCNIC_CMD_CONFIGURE_MAC_LEARNING      0xD
+#define QLCNIC_CMD_GET_STATISTICS              0xF
+#define QLCNIC_CMD_INTRPT_TEST                 0x11
+#define QLCNIC_CMD_SET_MTU                     0x12
+#define QLCNIC_CMD_READ_PHY                    0x13
+#define QLCNIC_CMD_WRITE_PHY                   0x14
+#define QLCNIC_CMD_READ_HW_REG                 0x15
+#define QLCNIC_CMD_GET_FLOW_CTL                        0x16
+#define QLCNIC_CMD_SET_FLOW_CTL                        0x17
+#define QLCNIC_CMD_READ_MAX_MTU                        0x18
+#define QLCNIC_CMD_READ_MAX_LRO                        0x19
+#define QLCNIC_CMD_MAC_ADDRESS                 0x1f
+#define QLCNIC_CMD_GET_PCI_INFO                        0x20
+#define QLCNIC_CMD_GET_NIC_INFO                        0x21
+#define QLCNIC_CMD_SET_NIC_INFO                        0x22
+#define QLCNIC_CMD_GET_ESWITCH_CAPABILITY      0x24
+#define QLCNIC_CMD_TOGGLE_ESWITCH              0x25
+#define QLCNIC_CMD_GET_ESWITCH_STATUS          0x26
+#define QLCNIC_CMD_SET_PORTMIRRORING           0x27
+#define QLCNIC_CMD_CONFIGURE_ESWITCH           0x28
+#define QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG     0x29
+#define QLCNIC_CMD_GET_ESWITCH_STATS           0x2a
+#define QLCNIC_CMD_CONFIG_PORT                 0x2e
+#define QLCNIC_CMD_TEMP_SIZE                   0x2f
+#define QLCNIC_CMD_GET_TEMP_HDR                        0x30
+#define QLCNIC_CMD_GET_MAC_STATS               0x37
+#define QLCNIC_CMD_SET_DRV_VER                 0x38
+#define QLCNIC_CMD_CONFIGURE_RSS               0x41
+#define QLCNIC_CMD_CONFIG_INTR_COAL            0x43
+#define QLCNIC_CMD_CONFIGURE_LED               0x44
+#define QLCNIC_CMD_CONFIG_MAC_VLAN             0x45
+#define QLCNIC_CMD_GET_LINK_EVENT              0x48
+#define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE       0x49
+#define QLCNIC_CMD_CONFIGURE_HW_LRO            0x4A
+#define QLCNIC_CMD_INIT_NIC_FUNC               0x60
+#define QLCNIC_CMD_STOP_NIC_FUNC               0x61
+#define QLCNIC_CMD_IDC_ACK                     0x63
+#define QLCNIC_CMD_SET_PORT_CONFIG             0x66
+#define QLCNIC_CMD_GET_PORT_CONFIG             0x67
+#define QLCNIC_CMD_GET_LINK_STATUS             0x68
+#define QLCNIC_CMD_SET_LED_CONFIG              0x69
+#define QLCNIC_CMD_GET_LED_CONFIG              0x6A
+#define QLCNIC_CMD_ADD_RCV_RINGS               0x0B
+
+#define QLCNIC_INTRPT_INTX                     1
+#define QLCNIC_INTRPT_MSIX                     3
+#define QLCNIC_INTRPT_ADD                      1
+#define QLCNIC_INTRPT_DEL                      2
+
+#define QLCNIC_GET_CURRENT_MAC                 1
+#define QLCNIC_SET_STATION_MAC                 2
+#define QLCNIC_GET_DEFAULT_MAC                 3
+#define QLCNIC_GET_FAC_DEF_MAC                 4
+#define QLCNIC_SET_FAC_DEF_MAC                 5
+
+#define QLCNIC_MBX_LINK_EVENT          0x8001
+#define QLCNIC_MBX_COMP_EVENT          0x8100
+#define QLCNIC_MBX_REQUEST_EVENT       0x8101
+#define QLCNIC_MBX_TIME_EXTEND_EVENT   0x8102
+#define QLCNIC_MBX_SFP_INSERT_EVENT    0x8130
+#define QLCNIC_MBX_SFP_REMOVE_EVENT    0x8131
+
+struct qlcnic_mailbox_metadata {
+       u32 cmd;
+       u32 in_args;
+       u32 out_args;
+};
+
+/* Mailbox ownership */
+#define QLCNIC_GET_OWNER(val)  ((val) & (BIT_0 | BIT_1))
+
+#define QLCNIC_SET_OWNER        1
+#define QLCNIC_CLR_OWNER        0
+#define QLCNIC_MBX_TIMEOUT      10000
+
+#define QLCNIC_MBX_RSP_OK      1
+#define QLCNIC_MBX_PORT_RSP_OK 0x1a
+
+struct qlcnic_pci_info;
+struct qlcnic_info;
+struct qlcnic_cmd_args;
+struct ethtool_stats;
+struct pci_device_id;
+struct qlcnic_host_sds_ring;
+struct qlcnic_host_tx_ring;
+struct qlcnic_host_tx_ring;
+struct qlcnic_hardware_context;
+struct qlcnic_adapter;
+
+int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong);
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
+int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);
+int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
+int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
+                        struct net_device *netdev);
+void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,
+                              u64 *uaddr, __le16 vlan_id);
+void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter);
+int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int);
+void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
+                              __be32, int);
+int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int);
+void qlcnic_82xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8);
+int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8);
+void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32);
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8);
+irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);
+int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
+                         struct qlcnic_cmd_args *);
+int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *,
+                                    struct qlcnic_host_tx_ring *tx_ring, int);
+int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *,
+                              struct qlcnic_adapter *, u32);
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
+int qlcnic_82xx_get_board_info(struct qlcnic_adapter *);
+int qlcnic_82xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_82xx_get_func_no(struct qlcnic_adapter *);
+int qlcnic_82xx_api_lock(struct qlcnic_adapter *);
+void qlcnic_82xx_api_unlock(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_enable(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_disable(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_del(struct qlcnic_adapter *);
+#endif                         /* __QLCNIC_HW_H_ */
index de79cde233def0a88f9bab32e2bfab295f7d785b..aa71ebaefdc0d3271e59f9a5dbaa4a820eaa659e 100644 (file)
@@ -5,11 +5,8 @@
  * See LICENSE.qlcnic for copyright and licensing details.
  */
 
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/if_vlan.h>
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
 
 struct crb_addr_pair {
        u32 addr;
@@ -166,13 +163,12 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_recv_context *recv_ctx;
        struct qlcnic_host_rds_ring *rds_ring;
-       struct qlcnic_host_tx_ring *tx_ring;
        int ring;
 
        recv_ctx = adapter->recv_ctx;
 
        if (recv_ctx->rds_rings == NULL)
-               goto skip_rds;
+               return;
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &recv_ctx->rds_rings[ring];
@@ -180,16 +176,6 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
                rds_ring->rx_buf_arr = NULL;
        }
        kfree(recv_ctx->rds_rings);
-
-skip_rds:
-       if (adapter->tx_ring == NULL)
-               return;
-
-       tx_ring = adapter->tx_ring;
-       vfree(tx_ring->cmd_buf_arr);
-       tx_ring->cmd_buf_arr = NULL;
-       kfree(adapter->tx_ring);
-       adapter->tx_ring = NULL;
 }
 
 int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
@@ -197,31 +183,11 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
        struct qlcnic_recv_context *recv_ctx;
        struct qlcnic_host_rds_ring *rds_ring;
        struct qlcnic_host_sds_ring *sds_ring;
-       struct qlcnic_host_tx_ring *tx_ring;
        struct qlcnic_rx_buffer *rx_buf;
        int ring, i, size;
 
-       struct qlcnic_cmd_buffer *cmd_buf_arr;
        struct net_device *netdev = adapter->netdev;
 
-       size = sizeof(struct qlcnic_host_tx_ring);
-       tx_ring = kzalloc(size, GFP_KERNEL);
-       if (tx_ring == NULL) {
-               dev_err(&netdev->dev, "failed to allocate tx ring struct\n");
-               return -ENOMEM;
-       }
-       adapter->tx_ring = tx_ring;
-
-       tx_ring->num_desc = adapter->num_txd;
-       tx_ring->txq = netdev_get_tx_queue(netdev, 0);
-
-       cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
-       if (cmd_buf_arr == NULL) {
-               dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n");
-               goto err_out;
-       }
-       tx_ring->cmd_buf_arr = cmd_buf_arr;
-
        recv_ctx = adapter->recv_ctx;
 
        size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring);
@@ -256,10 +222,11 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
                }
                rds_ring->rx_buf_arr = vzalloc(RCV_BUFF_RINGSIZE(rds_ring));
                if (rds_ring->rx_buf_arr == NULL) {
-                       dev_err(&netdev->dev, "Failed to allocate "
-                               "rx buffer ring %d\n", ring);
+                       dev_err(&netdev->dev,
+                               "Failed to allocate rx buffer ring %d\n", ring);
                        goto err_out;
                }
+
                INIT_LIST_HEAD(&rds_ring->free_list);
                /*
                 * Now go through all of them, set reference handles
@@ -327,7 +294,6 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
        long done = 0;
 
        cond_resched();
-
        while (done == 0) {
                done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
                done &= 2;
@@ -416,8 +382,8 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        u32 off;
        struct pci_dev *pdev = adapter->pdev;
 
-       QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
-       QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_RCVPEG_STATE, 0);
 
        /* Halt all the indiviual PEGs and other blocks */
        /* disable all I2Q */
@@ -564,8 +530,8 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
        msleep(1);
 
-       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
-       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
 
        return 0;
 }
@@ -576,7 +542,7 @@ static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
        int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
 
        do {
-               val = QLCRD32(adapter, CRB_CMDPEG_STATE);
+               val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CMDPEG_STATE);
 
                switch (val) {
                case PHAN_INITIALIZE_COMPLETE:
@@ -592,7 +558,8 @@ static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
 
        } while (--retries);
 
-       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE,
+                           PHAN_INITIALIZE_FAILED);
 
 out_err:
        dev_err(&adapter->pdev->dev, "Command Peg initialization not "
@@ -607,7 +574,7 @@ qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
        int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT;
 
        do {
-               val = QLCRD32(adapter, CRB_RCVPEG_STATE);
+               val = QLC_SHARED_REG_RD32(adapter, QLCNIC_RCVPEG_STATE);
 
                if (val == PHAN_PEG_RCV_INITIALIZED)
                        return 0;
@@ -638,7 +605,7 @@ qlcnic_check_fw_status(struct qlcnic_adapter *adapter)
        if (err)
                return err;
 
-       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
 
        return err;
 }
@@ -649,7 +616,7 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
        int timeo;
        u32 val;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+       val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
        val = QLC_DEV_GET_DRV(val, adapter->portnum);
        if ((val & 0x3) != QLCNIC_TYPE_NIC) {
                dev_err(&adapter->pdev->dev,
@@ -689,7 +656,7 @@ static int qlcnic_get_flt_entry(struct qlcnic_adapter *adapter, u8 region,
        }
 
        entry_size = flt_hdr.len - sizeof(struct qlcnic_flt_header);
-       flt_entry = (struct qlcnic_flt_entry *)vzalloc(entry_size);
+       flt_entry = vzalloc(entry_size);
        if (flt_entry == NULL) {
                dev_warn(&adapter->pdev->dev, "error allocating memory\n");
                return -EIO;
@@ -1096,11 +1063,13 @@ qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter)
        u32 heartbeat, ret = -EIO;
        int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
 
-       adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+       adapter->heartbeat = QLC_SHARED_REG_RD32(adapter,
+                                                QLCNIC_PEG_ALIVE_COUNTER);
 
        do {
                msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
-               heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+               heartbeat = QLC_SHARED_REG_RD32(adapter,
+                                               QLCNIC_PEG_ALIVE_COUNTER);
                if (heartbeat != adapter->heartbeat) {
                        ret = QLCNIC_RCODE_SUCCESS;
                        break;
@@ -1270,7 +1239,7 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
                return -EINVAL;
        }
 
-       QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID, QLCNIC_BDINFO_MAGIC);
        return 0;
 }
 
index 6f82812d0fab9e2e5697b3770d2c3c524b5daeab..fdf34836ef41a224a7b3141cec5c1c217bf83003 100644 (file)
@@ -5,9 +5,6 @@
 
 #include "qlcnic.h"
 
-#define QLCNIC_MAC_HASH(MAC)\
-       ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
-
 #define TX_ETHER_PKT   0x01
 #define TX_TCP_PKT     0x02
 #define TX_UDP_PKT     0x03
 #define QLCNIC_RESPONSE_DESC   0x05
 #define QLCNIC_LRO_DESC        0x12
 
+#define QLCNIC_TX_POLL_BUDGET          128
+#define QLCNIC_TCP_HDR_SIZE            20
+#define QLCNIC_TCP_TS_OPTION_SIZE      12
+#define QLCNIC_FETCH_RING_ID(handle)   ((handle) >> 63)
+#define QLCNIC_DESC_OWNER_FW           cpu_to_le64(STATUS_OWNER_PHANTOM)
+
+#define QLCNIC_TCP_TS_HDR_SIZE (QLCNIC_TCP_HDR_SIZE + QLCNIC_TCP_TS_OPTION_SIZE)
+
 /* for status field in status_desc */
 #define STATUS_CKSUM_LOOP      0
 #define STATUS_CKSUM_OK                2
 
-static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
-                                u64 uaddr, __le16 vlan_id,
-                                struct qlcnic_host_tx_ring *tx_ring)
+#define qlcnic_83xx_pktln(sts)         ((sts >> 32) & 0x3FFF)
+#define qlcnic_83xx_hndl(sts)          ((sts >> 48) & 0x7FFF)
+#define qlcnic_83xx_csum_status(sts)   ((sts >> 39) & 7)
+#define qlcnic_83xx_opcode(sts)        ((sts >> 42) & 0xF)
+#define qlcnic_83xx_vlan_tag(sts)      (((sts) >> 48) & 0xFFFF)
+#define qlcnic_83xx_lro_pktln(sts)     (((sts) >> 32) & 0x3FFF)
+#define qlcnic_83xx_l2_hdr_off(sts)    (((sts) >> 16) & 0xFF)
+#define qlcnic_83xx_l4_hdr_off(sts)    (((sts) >> 24) & 0xFF)
+#define qlcnic_83xx_pkt_cnt(sts)       (((sts) >> 16) & 0x7)
+#define qlcnic_83xx_is_tstamp(sts)     (((sts) >> 40) & 1)
+#define qlcnic_83xx_is_psh_bit(sts)    (((sts) >> 41) & 1)
+#define qlcnic_83xx_is_ip_align(sts)   (((sts) >> 46) & 1)
+#define qlcnic_83xx_has_vlan_tag(sts)  (((sts) >> 47) & 1)
+
+struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *,
+                                    struct qlcnic_host_rds_ring *, u16, u16);
+
+inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter,
+                                      struct qlcnic_host_tx_ring *tx_ring)
+{
+       writel(0, tx_ring->crb_intr_mask);
+}
+
+inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter,
+                                       struct qlcnic_host_tx_ring *tx_ring)
+{
+       writel(1, tx_ring->crb_intr_mask);
+}
+
+static inline u8 qlcnic_mac_hash(u64 mac)
+{
+       return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff));
+}
+
+static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
+                                       u16 handle, u8 ring_id)
+{
+       if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X)
+               return handle | (ring_id << 15);
+       else
+               return handle;
+}
+
+void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
+                              __le16 vlan_id)
 {
        struct cmd_desc_type0 *hwdesc;
        struct qlcnic_nic_req *req;
        struct qlcnic_mac_req *mac_req;
        struct qlcnic_vlan_req *vlan_req;
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
        u32 producer;
        u64 word;
 
@@ -128,14 +176,14 @@ static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
 }
 
 static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
-                              struct qlcnic_host_tx_ring *tx_ring,
                               struct cmd_desc_type0 *first_desc,
                               struct sk_buff *skb)
 {
-       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
        struct qlcnic_filter *fil, *tmp_fil;
        struct hlist_node *tmp_hnode, *n;
        struct hlist_head *head;
+       struct net_device *netdev = adapter->netdev;
+       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
        u64 src_addr = 0;
        __le16 vlan_id = 0;
        u8 hindex;
@@ -143,23 +191,26 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
        if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
                return;
 
-       if (adapter->fhash.fnum >= adapter->fhash.fmax)
+       if (adapter->fhash.fnum >= adapter->fhash.fmax) {
+               adapter->stats.mac_filter_limit_overrun++;
+               netdev_info(netdev, "Can not add more than %d mac addresses\n",
+                           adapter->fhash.fmax);
                return;
+       }
 
-       /* Only NPAR capable devices support vlan based learning*/
+       /* Only NPAR capable devices support vlan based learning */
        if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
                vlan_id = first_desc->vlan_TCI;
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
-       hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
+       hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
        head = &(adapter->fhash.fhead[hindex]);
 
        hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
                if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
-                           tmp_fil->vlan_id == vlan_id) {
-
+                   tmp_fil->vlan_id == vlan_id) {
                        if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
-                               qlcnic_change_filter(adapter, src_addr, vlan_id,
-                                                    tx_ring);
+                               qlcnic_change_filter(adapter, &src_addr,
+                                                    vlan_id);
                        tmp_fil->ftime = jiffies;
                        return;
                }
@@ -169,17 +220,13 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
        if (!fil)
                return;
 
-       qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
-
+       qlcnic_change_filter(adapter, &src_addr, vlan_id);
        fil->ftime = jiffies;
        fil->vlan_id = vlan_id;
        memcpy(fil->faddr, &src_addr, ETH_ALEN);
-
        spin_lock(&adapter->mac_learn_lock);
-
        hlist_add_head(&(fil->fnode), head);
        adapter->fhash.fnum++;
-
        spin_unlock(&adapter->mac_learn_lock);
 }
 
@@ -474,8 +521,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
                goto unwind_buff;
 
-       if (adapter->mac_learn)
-               qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
+       if (adapter->drv_mac_learn)
+               qlcnic_send_filter(adapter, first_desc, skb);
 
        adapter->stats.txbytes += skb->len;
        adapter->stats.xmitcalled++;
@@ -528,8 +575,8 @@ static int qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
        }
 
        skb_reserve(skb, NET_IP_ALIGN);
-       dma = pci_map_single(pdev, skb->data, rds_ring->dma_size,
-                            PCI_DMA_FROMDEVICE);
+       dma = pci_map_single(pdev, skb->data,
+                            rds_ring->dma_size, PCI_DMA_FROMDEVICE);
 
        if (pci_dma_mapping_error(pdev, dma)) {
                adapter->stats.rx_dma_map_error++;
@@ -544,12 +591,13 @@ static int qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
 }
 
 static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
-                                        struct qlcnic_host_rds_ring *rds_ring)
+                                       struct qlcnic_host_rds_ring *rds_ring,
+                                       u8 ring_id)
 {
        struct rcv_desc *pdesc;
        struct qlcnic_rx_buffer *buffer;
        int  count = 0;
-       uint32_t producer;
+       uint32_t producer, handle;
        struct list_head *head;
 
        if (!spin_trylock(&rds_ring->lock))
@@ -557,7 +605,6 @@ static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
 
        producer = rds_ring->producer;
        head = &rds_ring->free_list;
-
        while (!list_empty(head)) {
                buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
 
@@ -565,28 +612,29 @@ static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
                        if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
                                break;
                }
-
                count++;
                list_del(&buffer->list);
 
                /* make a rcv descriptor  */
                pdesc = &rds_ring->desc_head[producer];
-               pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+               handle = qlcnic_get_ref_handle(adapter,
+                                              buffer->ref_handle, ring_id);
+               pdesc->reference_handle = cpu_to_le16(handle);
                pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
                pdesc->addr_buffer = cpu_to_le64(buffer->dma);
                producer = get_next_index(producer, rds_ring->num_desc);
        }
-
        if (count) {
                rds_ring->producer = producer;
                writel((producer - 1) & (rds_ring->num_desc - 1),
                       rds_ring->crb_rcv_producer);
        }
-
        spin_unlock(&rds_ring->lock);
 }
 
-static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
+static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
+                                  struct qlcnic_host_tx_ring *tx_ring,
+                                  int budget)
 {
        u32 sw_consumer, hw_consumer;
        int i, done, count = 0;
@@ -594,7 +642,6 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
        struct pci_dev *pdev = adapter->pdev;
        struct net_device *netdev = adapter->netdev;
        struct qlcnic_skb_frag *frag;
-       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 
        if (!spin_trylock(&adapter->tx_clean_lock))
                return 1;
@@ -615,22 +662,19 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
                                               PCI_DMA_TODEVICE);
                                frag->dma = 0ULL;
                        }
-
                        adapter->stats.xmitfinished++;
                        dev_kfree_skb_any(buffer->skb);
                        buffer->skb = NULL;
                }
 
                sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
-               if (++count >= MAX_STATUS_HANDLE)
+               if (++count >= budget)
                        break;
        }
 
        if (count && netif_running(netdev)) {
                tx_ring->sw_consumer = sw_consumer;
-
                smp_mb();
-
                if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
                        if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
                                netif_wake_queue(netdev);
@@ -654,7 +698,6 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
         */
        hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
        done = (sw_consumer == hw_consumer);
-
        spin_unlock(&adapter->tx_clean_lock);
 
        return done;
@@ -662,16 +705,15 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
 
 static int qlcnic_poll(struct napi_struct *napi, int budget)
 {
+       int tx_complete, work_done;
        struct qlcnic_host_sds_ring *sds_ring;
        struct qlcnic_adapter *adapter;
-       int tx_complete, work_done;
 
        sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
        adapter = sds_ring->adapter;
-
-       tx_complete = qlcnic_process_cmd_ring(adapter);
+       tx_complete = qlcnic_process_cmd_ring(adapter, adapter->tx_ring,
+                                             budget);
        work_done = qlcnic_process_rcv_ring(sds_ring, budget);
-
        if ((work_done < budget) && tx_complete) {
                napi_complete(&sds_ring->napi);
                if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
@@ -804,26 +846,23 @@ static void qlcnic_handle_fw_message(int desc_cnt, int index,
        }
 }
 
-static struct sk_buff *
-qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
-                    struct qlcnic_host_rds_ring *rds_ring, u16 index,
-                    u16 cksum)
+struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+                                    struct qlcnic_host_rds_ring *ring,
+                                    u16 index, u16 cksum)
 {
        struct qlcnic_rx_buffer *buffer;
        struct sk_buff *skb;
 
-       buffer = &rds_ring->rx_buf_arr[index];
-
+       buffer = &ring->rx_buf_arr[index];
        if (unlikely(buffer->skb == NULL)) {
                WARN_ON(1);
                return NULL;
        }
 
-       pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
+       pci_unmap_single(adapter->pdev, buffer->dma, ring->dma_size,
                         PCI_DMA_FROMDEVICE);
 
        skb = buffer->skb;
-
        if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
                   (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
                adapter->stats.csummed++;
@@ -832,6 +871,7 @@ qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
                skb_checksum_none_assert(skb);
        }
 
+
        buffer->skb = NULL;
 
        return skb;
@@ -933,6 +973,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
        struct sk_buff *skb;
        struct qlcnic_host_rds_ring *rds_ring;
        struct iphdr *iph;
+       struct ipv6hdr *ipv6h;
        struct tcphdr *th;
        bool push, timestamp;
        int index, l2_hdr_offset, l4_hdr_offset;
@@ -976,12 +1017,21 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
        }
 
        skb->protocol = eth_type_trans(skb, netdev);
-       iph = (struct iphdr *)skb->data;
-       th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
-       length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
-       iph->tot_len = htons(length);
-       iph->check = 0;
-       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+       if (htons(skb->protocol) == ETH_P_IPV6) {
+               ipv6h = (struct ipv6hdr *)skb->data;
+               th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr));
+               length = (th->doff << 2) + lro_length;
+               ipv6h->payload_len = htons(length);
+       } else {
+               iph = (struct iphdr *)skb->data;
+               th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+               length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+               iph->tot_len = htons(length);
+               iph->check = 0;
+               iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+       }
+
        th->psh = push;
        th->seq = htonl(seq_number);
        length = skb->len;
@@ -1006,9 +1056,9 @@ int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
        struct list_head *cur;
        struct status_desc *desc;
        struct qlcnic_rx_buffer *rxbuf;
+       int opcode, desc_cnt, count = 0;
        u64 sts_data0, sts_data1;
-       __le64 owner_phantom = cpu_to_le64(STATUS_OWNER_PHANTOM);
-       int opcode, ring, desc_cnt, count = 0;
+       u8 ring;
        u32 consumer = sds_ring->consumer;
 
        while (count < max) {
@@ -1020,7 +1070,6 @@ int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
 
                desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
                opcode = qlcnic_get_sts_opcode(sts_data0);
-
                switch (opcode) {
                case QLCNIC_RXPKT_DESC:
                case QLCNIC_OLD_RXPKT_DESC:
@@ -1040,18 +1089,16 @@ int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
                default:
                        goto skip;
                }
-
                WARN_ON(desc_cnt > 1);
 
                if (likely(rxbuf))
                        list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
                else
                        adapter->stats.null_rxbuf++;
-
 skip:
                for (; desc_cnt > 0; desc_cnt--) {
                        desc = &sds_ring->desc_head[consumer];
-                       desc->status_desc_data[0] = owner_phantom;
+                       desc->status_desc_data[0] = QLCNIC_DESC_OWNER_FW;
                        consumer = get_next_index(consumer, sds_ring->num_desc);
                }
                count++;
@@ -1059,7 +1106,6 @@ skip:
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &adapter->recv_ctx->rds_rings[ring];
-
                if (!list_empty(&sds_ring->free_list[ring])) {
                        list_for_each(cur, &sds_ring->free_list[ring]) {
                                rxbuf = list_entry(cur, struct qlcnic_rx_buffer,
@@ -1072,7 +1118,7 @@ skip:
                        spin_unlock(&rds_ring->lock);
                }
 
-               qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
+               qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
        }
 
        if (count) {
@@ -1084,12 +1130,12 @@ skip:
 }
 
 void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
-                           struct qlcnic_host_rds_ring *rds_ring)
+                           struct qlcnic_host_rds_ring *rds_ring, u8 ring_id)
 {
        struct rcv_desc *pdesc;
        struct qlcnic_rx_buffer *buffer;
        int count = 0;
-       u32 producer;
+       u32 producer, handle;
        struct list_head *head;
 
        producer = rds_ring->producer;
@@ -1110,7 +1156,9 @@ void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
                /* make a rcv descriptor  */
                pdesc = &rds_ring->desc_head[producer];
                pdesc->addr_buffer = cpu_to_le64(buffer->dma);
-               pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+               handle = qlcnic_get_ref_handle(adapter, buffer->ref_handle,
+                                              ring_id);
+               pdesc->reference_handle = cpu_to_le16(handle);
                pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
                producer = get_next_index(producer, rds_ring->num_desc);
        }
@@ -1180,7 +1228,7 @@ static void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, int ring,
        return;
 }
 
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+void qlcnic_82xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
 {
        struct qlcnic_adapter *adapter = sds_ring->adapter;
        struct status_desc *desc;
@@ -1217,26 +1265,8 @@ void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
        writel(consumer, sds_ring->crb_sts_consumer);
 }
 
-void qlcnic_fetch_mac(u32 off1, u32 off2, u8 alt_mac, u8 *mac)
-{
-       u32 mac_low, mac_high;
-       int i;
-
-       mac_low = off1;
-       mac_high = off2;
-
-       if (alt_mac) {
-               mac_low |= (mac_low >> 16) | (mac_high << 16);
-               mac_high >>= 16;
-       }
-
-       for (i = 0; i < 2; i++)
-               mac[i] = (u8)(mac_high >> ((1 - i) * 8));
-       for (i = 2; i < 6; i++)
-               mac[i] = (u8)(mac_low >> ((5 - i) * 8));
-}
-
-int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
+int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
+                        struct net_device *netdev)
 {
        int ring, max_sds_rings;
        struct qlcnic_host_sds_ring *sds_ring;
@@ -1249,8 +1279,7 @@ int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
-
-               if (ring == max_sds_rings - 1)
+               if (ring == adapter->max_sds_rings - 1)
                        netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
                                       QLCNIC_NETDEV_WEIGHT / max_sds_rings);
                else
@@ -1258,10 +1287,15 @@ int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
                                       QLCNIC_NETDEV_WEIGHT*2);
        }
 
+       if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+               qlcnic_free_sds_rings(recv_ctx);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
-void qlcnic_napi_del(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)
 {
        int ring;
        struct qlcnic_host_sds_ring *sds_ring;
@@ -1273,9 +1307,10 @@ void qlcnic_napi_del(struct qlcnic_adapter *adapter)
        }
 
        qlcnic_free_sds_rings(adapter->recv_ctx);
+       qlcnic_free_tx_rings(adapter);
 }
 
-void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)
 {
        int ring;
        struct qlcnic_host_sds_ring *sds_ring;
@@ -1291,7 +1326,7 @@ void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
        }
 }
 
-void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
 {
        int ring;
        struct qlcnic_host_sds_ring *sds_ring;
@@ -1307,3 +1342,447 @@ void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
                napi_disable(&sds_ring->napi);
        }
 }
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
+                       struct qlcnic_host_sds_ring *sds_ring,
+                       u8 ring, u64 sts_data[])
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length, cksum;
+       u16 vid = 0xffff;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_83xx_hndl(sts_data[0]);
+       if (unlikely(index >= rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+       length = qlcnic_83xx_pktln(sts_data[0]);
+       cksum  = qlcnic_83xx_csum_status(sts_data[1]);
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+       if (!skb)
+               return buffer;
+
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
+
+       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+               adapter->stats.rxdropped++;
+               dev_kfree_skb(skb);
+               return buffer;
+       }
+
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       if (vid != 0xffff)
+               __vlan_hwaccel_put_tag(skb, vid);
+
+       napi_gro_receive(&sds_ring->napi, skb);
+
+       adapter->stats.rx_pkts++;
+       adapter->stats.rxbytes += length;
+
+       return buffer;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
+                       u8 ring, u64 sts_data[])
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct iphdr *iph;
+       struct ipv6hdr *ipv6h;
+       struct tcphdr *th;
+       bool push;
+       int l2_hdr_offset, l4_hdr_offset;
+       int index;
+       u16 lro_length, length, data_offset;
+       u16 vid = 0xffff;
+
+       if (unlikely(ring > adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_83xx_hndl(sts_data[0]);
+       if (unlikely(index > rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       lro_length = qlcnic_83xx_lro_pktln(sts_data[0]);
+       l2_hdr_offset = qlcnic_83xx_l2_hdr_off(sts_data[1]);
+       l4_hdr_offset = qlcnic_83xx_l4_hdr_off(sts_data[1]);
+       push = qlcnic_83xx_is_psh_bit(sts_data[1]);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+       if (!skb)
+               return buffer;
+       if (qlcnic_83xx_is_tstamp(sts_data[1]))
+               data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
+       else
+               data_offset = l4_hdr_offset + QLCNIC_TCP_HDR_SIZE;
+
+       skb_put(skb, lro_length + data_offset);
+       skb_pull(skb, l2_hdr_offset);
+
+       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+               adapter->stats.rxdropped++;
+               dev_kfree_skb(skb);
+               return buffer;
+       }
+
+       skb->protocol = eth_type_trans(skb, netdev);
+       if (ntohs(skb->protocol) == ETH_P_IPV6) {
+               ipv6h = (struct ipv6hdr *)skb->data;
+               th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr));
+
+               length = (th->doff << 2) + lro_length;
+               ipv6h->payload_len = htons(length);
+       } else {
+               iph = (struct iphdr *)skb->data;
+               th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+               length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+               iph->tot_len = htons(length);
+               iph->check = 0;
+               iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+       }
+
+       th->psh = push;
+       length = skb->len;
+
+       if (vid != 0xffff)
+               __vlan_hwaccel_put_tag(skb, vid);
+
+       netif_receive_skb(skb);
+
+       adapter->stats.lro_pkts++;
+       adapter->stats.lrobytes += length;
+       return buffer;
+}
+
+static int qlcnic_83xx_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring,
+                                       int max)
+{
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct list_head *cur;
+       struct status_desc *desc;
+       struct qlcnic_rx_buffer *rxbuf = NULL;
+       u8 ring;
+       u64 sts_data[2];
+       int count = 0, opcode;
+       u32 consumer = sds_ring->consumer;
+
+       while (count < max) {
+               desc = &sds_ring->desc_head[consumer];
+               sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+               opcode = qlcnic_83xx_opcode(sts_data[1]);
+               if (!opcode)
+                       break;
+               sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+               ring = QLCNIC_FETCH_RING_ID(sts_data[0]);
+
+               switch (opcode) {
+               case QLC_83XX_REG_DESC:
+                       rxbuf = qlcnic_83xx_process_rcv(adapter, sds_ring,
+                                                       ring, sts_data);
+                       break;
+               case QLC_83XX_LRO_DESC:
+                       rxbuf = qlcnic_83xx_process_lro(adapter, ring,
+                                                       sts_data);
+                       break;
+               default:
+                       dev_info(&adapter->pdev->dev,
+                                "Unkonwn opcode: 0x%x\n", opcode);
+                       goto skip;
+               }
+
+               if (likely(rxbuf))
+                       list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+               else
+                       adapter->stats.null_rxbuf++;
+skip:
+               desc = &sds_ring->desc_head[consumer];
+               /* Reset the descriptor */
+               desc->status_desc_data[1] = 0;
+               consumer = get_next_index(consumer, sds_ring->num_desc);
+               count++;
+       }
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &adapter->recv_ctx->rds_rings[ring];
+               if (!list_empty(&sds_ring->free_list[ring])) {
+                       list_for_each(cur, &sds_ring->free_list[ring]) {
+                               rxbuf = list_entry(cur, struct qlcnic_rx_buffer,
+                                                  list);
+                               qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+                       }
+                       spin_lock(&rds_ring->lock);
+                       list_splice_tail_init(&sds_ring->free_list[ring],
+                                             &rds_ring->free_list);
+                       spin_unlock(&rds_ring->lock);
+               }
+               qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
+       }
+       if (count) {
+               sds_ring->consumer = consumer;
+               writel(consumer, sds_ring->crb_sts_consumer);
+       }
+       return count;
+}
+
+static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
+{
+       int tx_complete;
+       int work_done;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_adapter *adapter;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+       adapter = sds_ring->adapter;
+       /* tx ring count = 1 */
+       tx_ring = adapter->tx_ring;
+
+       if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+               qlcnic_83xx_process_aen(adapter);
+
+       tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+       work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+       if ((work_done < budget) && tx_complete) {
+               napi_complete(&sds_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+                       qlcnic_83xx_enable_intr(adapter, sds_ring);
+       }
+
+       return work_done;
+}
+
+static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget)
+{
+       int work_done;
+       struct qlcnic_host_tx_ring *tx_ring;
+       struct qlcnic_adapter *adapter;
+
+       budget = QLCNIC_TX_POLL_BUDGET;
+       tx_ring = container_of(napi, struct qlcnic_host_tx_ring, napi);
+       adapter = tx_ring->adapter;
+       work_done = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+       if (work_done) {
+               napi_complete(&tx_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP , &adapter->state))
+                       qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+       }
+
+       return work_done;
+}
+
+static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget)
+{
+       int work_done;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_adapter *adapter;
+
+       sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+       adapter = sds_ring->adapter;
+       work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+       if (work_done < budget) {
+               napi_complete(&sds_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+                       qlcnic_83xx_enable_intr(adapter, sds_ring);
+       }
+
+       return work_done;
+}
+
+void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               napi_enable(&sds_ring->napi);
+               qlcnic_83xx_enable_intr(adapter, sds_ring);
+       }
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       napi_enable(&tx_ring->napi);
+                       qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+               }
+       }
+}
+
+void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               writel(1, sds_ring->crb_intr_mask);
+               napi_synchronize(&sds_ring->napi);
+               napi_disable(&sds_ring->napi);
+       }
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       qlcnic_83xx_disable_tx_intr(adapter, tx_ring);
+                       napi_synchronize(&tx_ring->napi);
+                       napi_disable(&tx_ring->napi);
+               }
+       }
+}
+
+int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,
+                        struct net_device *netdev)
+{
+       int ring, max_sds_rings;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+       if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
+               return -ENOMEM;
+
+       max_sds_rings = adapter->max_sds_rings;
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       netif_napi_add(netdev, &sds_ring->napi,
+                                      qlcnic_83xx_rx_poll,
+                                      QLCNIC_NETDEV_WEIGHT * 2);
+               else
+                       netif_napi_add(netdev, &sds_ring->napi,
+                                      qlcnic_83xx_poll,
+                                      QLCNIC_NETDEV_WEIGHT / max_sds_rings);
+       }
+
+       if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+               qlcnic_free_sds_rings(recv_ctx);
+               return -ENOMEM;
+       }
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       netif_napi_add(netdev, &tx_ring->napi,
+                                      qlcnic_83xx_msix_tx_poll,
+                                      QLCNIC_NETDEV_WEIGHT);
+               }
+       }
+
+       return 0;
+}
+
+void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               netif_napi_del(&sds_ring->napi);
+       }
+
+       qlcnic_free_sds_rings(adapter->recv_ctx);
+
+       if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       netif_napi_del(&tx_ring->napi);
+               }
+       }
+
+       qlcnic_free_tx_rings(adapter);
+}
+
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter,
+                                 int ring, u64 sts_data[])
+{
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+       index = qlcnic_83xx_hndl(sts_data[0]);
+       if (unlikely(index >= rds_ring->num_desc))
+               return;
+
+       length = qlcnic_83xx_pktln(sts_data[0]);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+       if (!skb)
+               return;
+
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
+
+       if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
+               adapter->ahw->diag_cnt++;
+       else
+               dump_skb(skb, adapter);
+
+       dev_kfree_skb_any(skb);
+       return;
+}
+
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct status_desc *desc;
+       u64 sts_data[2];
+       int ring, opcode;
+       u32 consumer = sds_ring->consumer;
+
+       desc = &sds_ring->desc_head[consumer];
+       sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+       sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+       opcode = qlcnic_83xx_opcode(sts_data[1]);
+       if (!opcode)
+               return;
+
+       ring = QLCNIC_FETCH_RING_ID(qlcnic_83xx_hndl(sts_data[0]));
+       qlcnic_83xx_process_rcv_diag(adapter, ring, sts_data);
+       desc = &sds_ring->desc_head[consumer];
+       desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+       consumer = get_next_index(consumer, sds_ring->num_desc);
+       sds_ring->consumer = consumer;
+       writel(consumer, sds_ring->crb_sts_consumer);
+}
index d833f592789120429d1c416f0c68b1e8ac528a8c..e6b363a7664f907c86d723ac44f0b8fbc76589b1 100644 (file)
@@ -5,20 +5,21 @@
  * See LICENSE.qlcnic for copyright and licensing details.
  */
 
-#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
 
 #include <linux/swab.h>
 #include <linux/dma-mapping.h>
+#include <linux/if_vlan.h>
 #include <net/ip.h>
 #include <linux/ipv6.h>
 #include <linux/inetdevice.h>
-#include <linux/sysfs.h>
 #include <linux/aer.h>
 #include <linux/log2.h>
+#include <linux/pci.h>
 
 MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
 MODULE_LICENSE("GPL");
@@ -29,28 +30,28 @@ char qlcnic_driver_name[] = "qlcnic";
 static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
        "Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
 
-static struct workqueue_struct *qlcnic_wq;
 static int qlcnic_mac_learn;
 module_param(qlcnic_mac_learn, int, 0444);
-MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
+MODULE_PARM_DESC(qlcnic_mac_learn,
+                "Mac Filter (0=learning is disabled, 1=Driver learning is enabled, 2=FDB learning is enabled)");
 
-static int qlcnic_use_msi = 1;
+int qlcnic_use_msi = 1;
 MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
 module_param_named(use_msi, qlcnic_use_msi, int, 0444);
 
-static int qlcnic_use_msi_x = 1;
+int qlcnic_use_msi_x = 1;
 MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
 module_param_named(use_msi_x, qlcnic_use_msi_x, int, 0444);
 
-static int qlcnic_auto_fw_reset = 1;
+int qlcnic_auto_fw_reset = 1;
 MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
 module_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644);
 
-static int qlcnic_load_fw_file;
+int qlcnic_load_fw_file;
 MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
 module_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
 
-static int qlcnic_config_npars;
+int qlcnic_config_npars;
 module_param(qlcnic_config_npars, int, 0444);
 MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
 
@@ -62,9 +63,6 @@ static void qlcnic_tx_timeout(struct net_device *netdev);
 static void qlcnic_attach_work(struct work_struct *work);
 static void qlcnic_fwinit_work(struct work_struct *work);
 static void qlcnic_fw_poll_work(struct work_struct *work);
-static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
-               work_func_t func, int delay);
-static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void qlcnic_poll_controller(struct net_device *netdev);
 #endif
@@ -77,9 +75,9 @@ static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
 static irqreturn_t qlcnic_intr(int irq, void *data);
 static irqreturn_t qlcnic_msi_intr(int irq, void *data);
 static irqreturn_t qlcnic_msix_intr(int irq, void *data);
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data);
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
-static void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long);
 static int qlcnic_start_firmware(struct qlcnic_adapter *);
 
 static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
@@ -93,15 +91,24 @@ static int qlcnic_vlan_rx_del(struct net_device *, u16);
 #define QLCNIC_IS_TSO_CAPABLE(adapter) \
        ((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
 
+static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X)
+               return ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX;
+       else
+               return 1;
+}
+
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
        .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
 
-#define PCI_DEVICE_ID_QLOGIC_QLE824X  0x8020
-
 static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
+       ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
        {0,}
 };
 
@@ -120,6 +127,32 @@ static const u32 msi_tgt_status[8] = {
        ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
 };
 
+static const u32 qlcnic_reg_tbl[] = {
+       0x1B20A8,       /* PEG_HALT_STAT1 */
+       0x1B20AC,       /* PEG_HALT_STAT2 */
+       0x1B20B0,       /* FW_HEARTBEAT */
+       0x1B2100,       /* LOCK ID */
+       0x1B2128,       /* FW_CAPABILITIES */
+       0x1B2138,       /* drv active */
+       0x1B2140,       /* dev state */
+       0x1B2144,       /* drv state */
+       0x1B2148,       /* drv scratch */
+       0x1B214C,       /* dev partition info */
+       0x1B2174,       /* drv idc ver */
+       0x1B2150,       /* fw version major */
+       0x1B2154,       /* fw version minor */
+       0x1B2158,       /* fw version sub */
+       0x1B219C,       /* npar state */
+       0x1B21FC,       /* FW_IMG_VALID */
+       0x1B2250,       /* CMD_PEG_STATE */
+       0x1B233C,       /* RCV_PEG_STATE */
+       0x1B23B4,       /* ASIC TEMP */
+       0x1B216C,       /* FW api */
+       0x1B2170,       /* drv op mode */
+       0x13C010,       /* flash lock */
+       0x13C014,       /* flash unlock */
+};
+
 static const struct qlcnic_board_info qlcnic_boards[] = {
        {0x1077, 0x8020, 0x1077, 0x203,
         "8200 Series Single Port 10GbE Converged Network Adapter"
@@ -143,6 +176,7 @@ static const struct qlcnic_board_info qlcnic_boards[] = {
 };
 
 #define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
+#define QLC_MAX_SDS_RINGS      8
 
 static const
 struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
@@ -164,35 +198,6 @@ void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
        recv_ctx->sds_rings = NULL;
 }
 
-static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
-{
-       memset(&adapter->stats, 0, sizeof(adapter->stats));
-}
-
-static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
-{
-       u32 control;
-       int pos;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               pci_read_config_dword(pdev, pos, &control);
-               if (enable)
-                       control |= PCI_MSIX_FLAGS_ENABLE;
-               else
-                       control = 0;
-               pci_write_config_dword(pdev, pos, control);
-       }
-}
-
-static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
-{
-       int i;
-
-       for (i = 0; i < count; i++)
-               adapter->msix_entries[i].entry = i;
-}
-
 static int
 qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
 {
@@ -204,12 +209,11 @@ qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
                return -EIO;
 
        memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
-       memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
        memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
 
        /* set station address */
 
-       if (!is_valid_ether_addr(netdev->perm_addr))
+       if (!is_valid_ether_addr(netdev->dev_addr))
                dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
                                        netdev->dev_addr);
 
@@ -225,7 +229,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
                return -EOPNOTSUPP;
 
        if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
+               return -EINVAL;
 
        if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
                netif_device_detach(netdev);
@@ -243,6 +247,85 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
        return 0;
 }
 
+static int qlcnic_fdb_del(struct ndmsg *ndm, struct net_device *netdev,
+                       const unsigned char *addr)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int err = -EOPNOTSUPP;
+
+       if (!adapter->fdb_mac_learn) {
+               pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+                       __func__);
+               return err;
+       }
+
+       if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
+               if (is_unicast_ether_addr(addr))
+                       err = qlcnic_nic_del_mac(adapter, addr);
+               else if (is_multicast_ether_addr(addr))
+                       err = dev_mc_del(netdev, addr);
+               else
+                       err =  -EINVAL;
+       }
+       return err;
+}
+
+static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+                       struct net_device *netdev,
+                       const unsigned char *addr, u16 flags)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int err = 0;
+
+       if (!adapter->fdb_mac_learn) {
+               pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+                       __func__);
+               return -EOPNOTSUPP;
+       }
+
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+               pr_info("%s: FDB e-switch is not enabled\n", __func__);
+               return -EOPNOTSUPP;
+       }
+
+       if (ether_addr_equal(addr, adapter->mac_addr))
+               return err;
+
+       if (is_unicast_ether_addr(addr))
+               err = qlcnic_nic_add_mac(adapter, addr);
+       else if (is_multicast_ether_addr(addr))
+               err = dev_mc_add_excl(netdev, addr);
+       else
+               err = -EINVAL;
+
+       return err;
+}
+
+static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,
+                       struct net_device *netdev, int idx)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+       if (!adapter->fdb_mac_learn) {
+               pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+                       __func__);
+               return -EOPNOTSUPP;
+       }
+
+       if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+               idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
+
+       return idx;
+}
+
+static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
+{
+       while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               usleep_range(10000, 11000);
+
+       cancel_delayed_work_sync(&adapter->fw_work);
+}
+
 static const struct net_device_ops qlcnic_netdev_ops = {
        .ndo_open          = qlcnic_open,
        .ndo_stop          = qlcnic_close,
@@ -257,6 +340,9 @@ static const struct net_device_ops qlcnic_netdev_ops = {
        .ndo_tx_timeout    = qlcnic_tx_timeout,
        .ndo_vlan_rx_add_vid    = qlcnic_vlan_rx_add,
        .ndo_vlan_rx_kill_vid   = qlcnic_vlan_rx_del,
+       .ndo_fdb_add            = qlcnic_fdb_add,
+       .ndo_fdb_del            = qlcnic_fdb_del,
+       .ndo_fdb_dump           = qlcnic_fdb_dump,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = qlcnic_poll_controller,
 #endif
@@ -267,50 +353,126 @@ static const struct net_device_ops qlcnic_netdev_failed_ops = {
 };
 
 static struct qlcnic_nic_template qlcnic_ops = {
-       .config_bridged_mode = qlcnic_config_bridged_mode,
-       .config_led = qlcnic_config_led,
-       .start_firmware = qlcnic_start_firmware
+       .config_bridged_mode    = qlcnic_config_bridged_mode,
+       .config_led             = qlcnic_82xx_config_led,
+       .start_firmware         = qlcnic_82xx_start_firmware,
+       .request_reset          = qlcnic_82xx_dev_request_reset,
+       .cancel_idc_work        = qlcnic_82xx_cancel_idc_work,
+       .napi_add               = qlcnic_82xx_napi_add,
+       .napi_del               = qlcnic_82xx_napi_del,
+       .config_ipaddr          = qlcnic_82xx_config_ipaddr,
+       .clear_legacy_intr      = qlcnic_82xx_clear_legacy_intr,
+};
+
+struct qlcnic_nic_template qlcnic_vf_ops = {
+       .config_bridged_mode    = qlcnicvf_config_bridged_mode,
+       .config_led             = qlcnicvf_config_led,
+       .start_firmware         = qlcnicvf_start_firmware
 };
 
-static struct qlcnic_nic_template qlcnic_vf_ops = {
-       .config_bridged_mode = qlcnicvf_config_bridged_mode,
-       .config_led = qlcnicvf_config_led,
-       .start_firmware = qlcnicvf_start_firmware
+static struct qlcnic_hardware_ops qlcnic_hw_ops = {
+       .read_crb                       = qlcnic_82xx_read_crb,
+       .write_crb                      = qlcnic_82xx_write_crb,
+       .read_reg                       = qlcnic_82xx_hw_read_wx_2M,
+       .write_reg                      = qlcnic_82xx_hw_write_wx_2M,
+       .get_mac_address                = qlcnic_82xx_get_mac_address,
+       .setup_intr                     = qlcnic_82xx_setup_intr,
+       .alloc_mbx_args                 = qlcnic_82xx_alloc_mbx_args,
+       .mbx_cmd                        = qlcnic_82xx_issue_cmd,
+       .get_func_no                    = qlcnic_82xx_get_func_no,
+       .api_lock                       = qlcnic_82xx_api_lock,
+       .api_unlock                     = qlcnic_82xx_api_unlock,
+       .add_sysfs                      = qlcnic_82xx_add_sysfs,
+       .remove_sysfs                   = qlcnic_82xx_remove_sysfs,
+       .process_lb_rcv_ring_diag       = qlcnic_82xx_process_rcv_ring_diag,
+       .create_rx_ctx                  = qlcnic_82xx_fw_cmd_create_rx_ctx,
+       .create_tx_ctx                  = qlcnic_82xx_fw_cmd_create_tx_ctx,
+       .setup_link_event               = qlcnic_82xx_linkevent_request,
+       .get_nic_info                   = qlcnic_82xx_get_nic_info,
+       .get_pci_info                   = qlcnic_82xx_get_pci_info,
+       .set_nic_info                   = qlcnic_82xx_set_nic_info,
+       .change_macvlan                 = qlcnic_82xx_sre_macaddr_change,
+       .napi_enable                    = qlcnic_82xx_napi_enable,
+       .napi_disable                   = qlcnic_82xx_napi_disable,
+       .config_intr_coal               = qlcnic_82xx_config_intr_coalesce,
+       .config_rss                     = qlcnic_82xx_config_rss,
+       .config_hw_lro                  = qlcnic_82xx_config_hw_lro,
+       .config_loopback                = qlcnic_82xx_set_lb_mode,
+       .clear_loopback                 = qlcnic_82xx_clear_lb_mode,
+       .config_promisc_mode            = qlcnic_82xx_nic_set_promisc,
+       .change_l2_filter               = qlcnic_82xx_change_filter,
+       .get_board_info                 = qlcnic_82xx_get_board_info,
 };
 
-static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
+int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
 {
        struct pci_dev *pdev = adapter->pdev;
-       int err = -1;
+       int err = -1, i;
+       int max_tx_rings;
+
+       if (!adapter->msix_entries) {
+               adapter->msix_entries = kcalloc(num_msix,
+                                               sizeof(struct msix_entry),
+                                               GFP_KERNEL);
+               if (!adapter->msix_entries) {
+                       dev_err(&pdev->dev, "failed allocating msix_entries\n");
+                       return -ENOMEM;
+               }
+       }
 
        adapter->max_sds_rings = 1;
        adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
-       qlcnic_set_msix_bit(pdev, 0);
 
        if (adapter->ahw->msix_supported) {
  enable_msix:
-               qlcnic_init_msix_entries(adapter, num_msix);
+               for (i = 0; i < num_msix; i++)
+                       adapter->msix_entries[i].entry = i;
                err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
                if (err == 0) {
                        adapter->flags |= QLCNIC_MSIX_ENABLED;
-                       qlcnic_set_msix_bit(pdev, 1);
-
-                       adapter->max_sds_rings = num_msix;
-
+                       if (qlcnic_83xx_check(adapter)) {
+                               adapter->ahw->num_msix = num_msix;
+                               /* subtract mail box and tx ring vectors */
+                               max_tx_rings = adapter->max_drv_tx_rings;
+                               adapter->max_sds_rings = num_msix -
+                                                        max_tx_rings - 1;
+                       } else {
+                               adapter->max_sds_rings = num_msix;
+                       }
                        dev_info(&pdev->dev, "using msi-x interrupts\n");
                        return err;
-               }
-               if (err > 0) {
-                       num_msix = rounddown_pow_of_two(err);
-                       if (num_msix)
+               } else if (err > 0) {
+                       dev_info(&pdev->dev,
+                                "Unable to allocate %d MSI-X interrupt vectors\n",
+                                num_msix);
+                       if (qlcnic_83xx_check(adapter)) {
+                               if (err < QLC_83XX_MINIMUM_VECTOR)
+                                       return err;
+                               err -= (adapter->max_drv_tx_rings + 1);
+                               num_msix = rounddown_pow_of_two(err);
+                               num_msix += (adapter->max_drv_tx_rings + 1);
+                       } else {
+                               num_msix = rounddown_pow_of_two(err);
+                       }
+
+                       if (num_msix) {
+                               dev_info(&pdev->dev,
+                                        "Trying %d MSI-X interrupt vectors\n",
+                                        num_msix);
                                goto enable_msix;
+                       }
+               } else {
+                       dev_info(&pdev->dev, "Failed to get %d vectors\n",
+                                num_msix);
                }
        }
+
        return err;
 }
 
-static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
+static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
 {
+       int err = 0;
        u32 offset, mask_reg;
        const struct qlcnic_legacy_intr_set *legacy_intrp;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -323,8 +485,10 @@ static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
                                                            offset);
                dev_info(&pdev->dev, "using msi interrupts\n");
                adapter->msix_entries[0].vector = pdev->irq;
-               return;
+               return err;
        }
+       if (qlcnic_use_msi || qlcnic_use_msi_x)
+               return -EOPNOTSUPP;
 
        legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
        adapter->ahw->int_vec_bit = legacy_intrp->int_vec_bit;
@@ -336,32 +500,47 @@ static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
        adapter->crb_int_state_reg = qlcnic_get_ioaddr(ahw, ISR_INT_STATE_REG);
        dev_info(&pdev->dev, "using legacy interrupts\n");
        adapter->msix_entries[0].vector = pdev->irq;
+       return err;
 }
 
-static void
-qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
 {
-       int num_msix;
+       int num_msix, err = 0;
 
-       if (adapter->ahw->msix_supported) {
+       if (!num_intr)
+               num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+
+       if (adapter->ahw->msix_supported)
                num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
-                               QLCNIC_DEF_NUM_STS_DESC_RINGS));
-       else
+                                               num_intr));
+       else
                num_msix = 1;
 
-       if (!qlcnic_enable_msix(adapter, num_msix))
-               return;
+       err = qlcnic_enable_msix(adapter, num_msix);
+       if (err == -ENOMEM || !err)
+               return err;
 
-       qlcnic_enable_msi_legacy(adapter);
+       err = qlcnic_enable_msi_legacy(adapter);
+       if (!err)
+               return err;
+
+       return -EIO;
 }
 
-static void
-qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
+void qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
 {
        if (adapter->flags & QLCNIC_MSIX_ENABLED)
                pci_disable_msix(adapter->pdev);
        if (adapter->flags & QLCNIC_MSI_ENABLED)
                pci_disable_msi(adapter->pdev);
+
+       kfree(adapter->msix_entries);
+       adapter->msix_entries = NULL;
+
+       if (adapter->ahw->intr_tbl) {
+               vfree(adapter->ahw->intr_tbl);
+               adapter->ahw->intr_tbl = NULL;
+       }
 }
 
 static void
@@ -371,7 +550,36 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
                iounmap(adapter->ahw->pci_base0);
 }
 
-static int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+static int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_pci_info *pci_info;
+       int ret;
+
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+               switch (adapter->ahw->port_type) {
+               case QLCNIC_GBE:
+                       adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_GBE_PORTS;
+                       break;
+               case QLCNIC_XGBE:
+                       adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_XG_PORTS;
+                       break;
+               }
+               return 0;
+       }
+
+       if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+               return 0;
+
+       pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+       if (!pci_info)
+               return -ENOMEM;
+
+       ret = qlcnic_get_pci_info(adapter, pci_info);
+       kfree(pci_info);
+       return ret;
+}
+
+int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_pci_info *pci_info;
        int i, ret = 0, j = 0;
@@ -423,8 +631,11 @@ static int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
                j++;
        }
 
-       for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+       for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) {
                adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+               if (qlcnic_83xx_check(adapter))
+                       qlcnic_enable_eswitch(adapter, i, 1);
+       }
 
        kfree(pci_info);
        return 0;
@@ -462,40 +673,31 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
                                        QLC_DEV_SET_DRV(0xf, id));
                }
        } else {
-               data = QLCRD32(adapter, QLCNIC_DRV_OP_MODE);
+               data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
                data = (data & ~QLC_DEV_SET_DRV(0xf, ahw->pci_func)) |
                        (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
                                         ahw->pci_func));
        }
-       QLCWR32(adapter, QLCNIC_DRV_OP_MODE, data);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_DRV_OP_MODE, data);
        qlcnic_api_unlock(adapter);
 err_lock:
        return ret;
 }
 
-static void
-qlcnic_check_vf(struct qlcnic_adapter *adapter)
+static void qlcnic_check_vf(struct qlcnic_adapter *adapter,
+                           const struct pci_device_id *ent)
 {
-       void __iomem *msix_base_addr;
-       void __iomem *priv_op;
-       u32 func;
-       u32 msix_base;
        u32 op_mode, priv_level;
 
        /* Determine FW API version */
-       adapter->ahw->fw_hal_version = readl(adapter->ahw->pci_base0 +
-                                            QLCNIC_FW_API);
+       adapter->ahw->fw_hal_version = QLC_SHARED_REG_RD32(adapter,
+                                                          QLCNIC_FW_API);
 
        /* Find PCI function number */
-       pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
-       msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
-       msix_base = readl(msix_base_addr);
-       func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
-       adapter->ahw->pci_func = func;
+       qlcnic_get_func_no(adapter);
 
        /* Determine function privilege level */
-       priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
-       op_mode = readl(priv_op);
+       op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
        if (op_mode == QLC_DEV_DRV_DEFAULT)
                priv_level = QLCNIC_MGMT_FUNC;
        else
@@ -512,12 +714,16 @@ qlcnic_check_vf(struct qlcnic_adapter *adapter)
 }
 
 #define QLCNIC_82XX_BAR0_LENGTH 0x00200000UL
+#define QLCNIC_83XX_BAR0_LENGTH 0x4000
 static void qlcnic_get_bar_length(u32 dev_id, ulong *bar)
 {
        switch (dev_id) {
        case PCI_DEVICE_ID_QLOGIC_QLE824X:
                *bar = QLCNIC_82XX_BAR0_LENGTH;
                break;
+       case PCI_DEVICE_ID_QLOGIC_QLE834X:
+               *bar = QLCNIC_83XX_BAR0_LENGTH;
+               break;
        default:
                *bar = 0;
        }
@@ -547,6 +753,7 @@ static int qlcnic_setup_pci_map(struct pci_dev *pdev,
        }
 
        dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+
        ahw->pci_base0 = mem_ptr0;
        ahw->pci_len0 = pci_len0;
        offset = QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(ahw->pci_func));
@@ -581,19 +788,26 @@ static void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name)
 static void
 qlcnic_check_options(struct qlcnic_adapter *adapter)
 {
+       int err;
        u32 fw_major, fw_minor, fw_build, prev_fw_version;
        struct pci_dev *pdev = adapter->pdev;
-       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
 
        prev_fw_version = adapter->fw_version;
 
-       fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
-       fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
-       fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+       fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+       fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+       fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
 
        adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
 
-       if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
+       err = qlcnic_get_board_info(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "Error getting board config info.\n");
+               return;
+       }
+       if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
                if (fw_dump->tmpl_hdr == NULL ||
                                adapter->fw_version > prev_fw_version) {
                        if (fw_dump->tmpl_hdr)
@@ -604,8 +818,9 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
                }
        }
 
-       dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
-                       fw_major, fw_minor, fw_build);
+       dev_info(&pdev->dev, "Driver v%s, firmware v%d.%d.%d\n",
+                QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
+
        if (adapter->ahw->port_type == QLCNIC_XGBE) {
                if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
                        adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
@@ -648,9 +863,19 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
        adapter->ahw->max_tx_ques = nic_info.max_tx_ques;
        adapter->ahw->max_rx_ques = nic_info.max_rx_ques;
        adapter->ahw->capabilities = nic_info.capabilities;
+
+       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+               u32 temp;
+               temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+               adapter->ahw->capabilities2 = temp;
+       }
        adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
        adapter->ahw->max_mtu = nic_info.max_mtu;
 
+       /* Disable NPAR for 83XX */
+       if (qlcnic_83xx_check(adapter))
+               return err;
+
        if (adapter->ahw->capabilities & BIT_6)
                adapter->flags |= QLCNIC_ESWITCH_ENABLED;
        else
@@ -709,7 +934,7 @@ void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
        qlcnic_set_netdev_features(adapter, esw_cfg);
 }
 
-static int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_esw_func_cfg esw_cfg;
 
@@ -730,14 +955,17 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
                struct qlcnic_esw_func_cfg *esw_cfg)
 {
        struct net_device *netdev = adapter->netdev;
-       netdev_features_t features, vlan_features;
+       unsigned long features, vlan_features;
+
+       if (qlcnic_83xx_check(adapter))
+               return;
 
        features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
-                       NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+                   NETIF_F_IPV6_CSUM | NETIF_F_GRO);
        vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
-                       NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER);
+                       NETIF_F_IPV6_CSUM);
 
-       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+       if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
                features |= (NETIF_F_TSO | NETIF_F_TSO6);
                vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
        }
@@ -747,12 +975,19 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
 
        if (esw_cfg->offload_flags & BIT_0) {
                netdev->features |= features;
-               if (!(esw_cfg->offload_flags & BIT_1))
+               adapter->rx_csum = 1;
+               if (!(esw_cfg->offload_flags & BIT_1)) {
                        netdev->features &= ~NETIF_F_TSO;
-               if (!(esw_cfg->offload_flags & BIT_2))
+                       features &= ~NETIF_F_TSO;
+               }
+               if (!(esw_cfg->offload_flags & BIT_2)) {
                        netdev->features &= ~NETIF_F_TSO6;
+                       features &= ~NETIF_F_TSO6;
+               }
        } else {
                netdev->features &= ~features;
+               features &= ~features;
+               adapter->rx_csum = 0;
        }
 
        netdev->vlan_features = (features & vlan_features);
@@ -761,7 +996,6 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
 static int
 qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
 {
-       void __iomem *priv_op;
        u32 op_mode, priv_level;
        int err = 0;
 
@@ -772,8 +1006,7 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
        if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
                return 0;
 
-       priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
-       op_mode = readl(priv_op);
+       op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
        priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
 
        if (op_mode == QLC_DEV_DRV_DEFAULT)
@@ -805,7 +1038,7 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
        return err;
 }
 
-static int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_esw_func_cfg esw_cfg;
        struct qlcnic_npar_info *npar;
@@ -838,6 +1071,7 @@ static int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
        return 0;
 }
 
+
 static int
 qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
                        struct qlcnic_npar_info *npar, int pci_func)
@@ -861,7 +1095,7 @@ qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-static int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
+int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
 {
        int i, err;
        struct qlcnic_npar_info *npar;
@@ -877,8 +1111,7 @@ static int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
                npar = &adapter->npars[i];
                pci_func = npar->pci_func;
                memset(&nic_info, 0, sizeof(struct qlcnic_info));
-               err = qlcnic_get_nic_info(adapter,
-                                         &nic_info, pci_func);
+               err = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
                if (err)
                        return err;
                nic_info.min_tx_bw = npar->min_bw;
@@ -909,10 +1142,12 @@ static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
        if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
                return 0;
 
-       npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+       npar_state = QLC_SHARED_REG_RD32(adapter,
+                                        QLCNIC_CRB_DEV_NPAR_STATE);
        while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
                msleep(1000);
-               npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+               npar_state = QLC_SHARED_REG_RD32(adapter,
+                                                QLCNIC_CRB_DEV_NPAR_STATE);
        }
        if (!npar_opt_timeo) {
                dev_err(&adapter->pdev->dev,
@@ -941,11 +1176,12 @@ qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)
 
        qlcnic_dev_set_npar_ready(adapter);
 
+       if (qlcnic_83xx_check(adapter))
+               qlcnic_83xx_register_nic_idc_func(adapter, 1);
        return err;
 }
 
-static int
-qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter)
 {
        int err;
 
@@ -985,9 +1221,8 @@ check_fw_status:
        if (err)
                goto err_out;
 
-       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
        qlcnic_idc_debug_info(adapter, 1);
-
        err = qlcnic_check_eswitch_mode(adapter);
        if (err) {
                dev_err(&adapter->pdev->dev,
@@ -1005,7 +1240,7 @@ check_fw_status:
        return 0;
 
 err_out:
-       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
        dev_err(&adapter->pdev->dev, "Device state set to failed\n");
 
        qlcnic_release_firmware(adapter);
@@ -1017,6 +1252,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
 {
        irq_handler_t handler;
        struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
        int err, ring;
 
        unsigned long flags = 0;
@@ -1024,7 +1260,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
-               handler = qlcnic_tmp_intr;
+               if (qlcnic_82xx_check(adapter))
+                       handler = qlcnic_tmp_intr;
                if (!QLCNIC_IS_MSI_FAMILY(adapter))
                        flags |= IRQF_SHARED;
 
@@ -1040,15 +1277,32 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
        }
        adapter->irq = netdev->irq;
 
-       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-               sds_ring = &recv_ctx->sds_rings[ring];
-               sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
-               err = request_irq(sds_ring->irq, handler,
-                                 flags, sds_ring->name, sds_ring);
-               if (err)
-                       return err;
+       if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &recv_ctx->sds_rings[ring];
+                       snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
+                                "%s[%d]", netdev->name, ring);
+                       err = request_irq(sds_ring->irq, handler, flags,
+                                         sds_ring->name, sds_ring);
+                       if (err)
+                               return err;
+               }
+               if (qlcnic_83xx_check(adapter) &&
+                   (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+                       handler = qlcnic_msix_tx_intr;
+                       for (ring = 0; ring < adapter->max_drv_tx_rings;
+                            ring++) {
+                               tx_ring = &adapter->tx_ring[ring];
+                               snprintf(tx_ring->name, sizeof(int) + IFNAMSIZ,
+                                        "%s[%d]", netdev->name,
+                               adapter->max_sds_rings + ring);
+                               err = request_irq(tx_ring->irq, handler, flags,
+                                                 tx_ring->name, tx_ring);
+                               if (err)
+                                       return err;
+                       }
+               }
        }
-
        return 0;
 }
 
@@ -1057,17 +1311,27 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
 {
        int ring;
        struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
 
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-               sds_ring = &recv_ctx->sds_rings[ring];
-               free_irq(sds_ring->irq, sds_ring);
+       if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &recv_ctx->sds_rings[ring];
+                       free_irq(sds_ring->irq, sds_ring);
+               }
+               if (qlcnic_83xx_check(adapter)) {
+                       for (ring = 0; ring < adapter->max_drv_tx_rings;
+                            ring++) {
+                               tx_ring = &adapter->tx_ring[ring];
+                               if (tx_ring->irq)
+                                       free_irq(tx_ring->irq, tx_ring);
+                       }
+               }
        }
 }
 
-static int
-__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        int ring;
        u32 capab2;
@@ -1093,7 +1357,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &adapter->recv_ctx->rds_rings[ring];
-               qlcnic_post_rx_buffers(adapter, rds_ring);
+               qlcnic_post_rx_buffers(adapter, rds_ring, ring);
        }
 
        qlcnic_set_multi(netdev);
@@ -1118,10 +1382,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        return 0;
 }
 
-/* Usage: During resume and firmware recovery module.*/
-
-static int
-qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+int qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        int err = 0;
 
@@ -1133,8 +1394,7 @@ qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        return err;
 }
 
-static void
-__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
                return;
@@ -1166,8 +1426,7 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
 /* Usage: During suspend and firmware recovery module */
 
-static void
-qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        rtnl_lock();
        if (netif_running(netdev))
@@ -1176,7 +1435,7 @@ qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
 }
 
-static int
+int
 qlcnic_attach(struct qlcnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
@@ -1222,8 +1481,7 @@ err_out_napi_del:
        return err;
 }
 
-static void
-qlcnic_detach(struct qlcnic_adapter *adapter)
+void qlcnic_detach(struct qlcnic_adapter *adapter)
 {
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
                return;
@@ -1249,7 +1507,10 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx->sds_rings[ring];
-                       qlcnic_disable_int(sds_ring);
+                       if (qlcnic_83xx_check(adapter))
+                               writel(1, sds_ring->crb_intr_mask);
+                       else
+                               qlcnic_disable_int(sds_ring);
                }
        }
 
@@ -1272,21 +1533,11 @@ out:
 static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
 {
        int err = 0;
-       adapter->ahw = kzalloc(sizeof(struct qlcnic_hardware_context),
-                               GFP_KERNEL);
-       if (!adapter->ahw) {
-               dev_err(&adapter->pdev->dev,
-                       "Failed to allocate recv ctx resources for adapter\n");
-               err = -ENOMEM;
-               goto err_out;
-       }
        adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
                                GFP_KERNEL);
        if (!adapter->recv_ctx) {
                dev_err(&adapter->pdev->dev,
                        "Failed to allocate recv ctx resources for adapter\n");
-               kfree(adapter->ahw);
-               adapter->ahw = NULL;
                err = -ENOMEM;
                goto err_out;
        }
@@ -1294,6 +1545,8 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
        adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
        adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
        adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+       /* clear stats */
+       memset(&adapter->stats, 0, sizeof(adapter->stats));
 err_out:
        return err;
 }
@@ -1307,8 +1560,9 @@ static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter)
                vfree(adapter->ahw->fw_dump.tmpl_hdr);
                adapter->ahw->fw_dump.tmpl_hdr = NULL;
        }
-       kfree(adapter->ahw);
-       adapter->ahw = NULL;
+
+       kfree(adapter->ahw->reset.buff);
+       adapter->ahw->fw_dump.tmpl_hdr = NULL;
 }
 
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
@@ -1328,6 +1582,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
 
        adapter->max_sds_rings = 1;
        adapter->ahw->diag_test = test;
+       adapter->ahw->linkup = 0;
 
        ret = qlcnic_attach(adapter);
        if (ret) {
@@ -1344,13 +1599,16 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &adapter->recv_ctx->rds_rings[ring];
-               qlcnic_post_rx_buffers(adapter, rds_ring);
+               qlcnic_post_rx_buffers(adapter, rds_ring, ring);
        }
 
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx->sds_rings[ring];
-                       qlcnic_enable_int(sds_ring);
+                       if (qlcnic_82xx_check(adapter))
+                               qlcnic_enable_int(sds_ring);
+                       else
+                               qlcnic_83xx_enable_intr(adapter, sds_ring);
                }
        }
 
@@ -1382,6 +1640,7 @@ qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
        netif_device_attach(netdev);
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       dev_err(&adapter->pdev->dev, "%s:\n", __func__);
        return 0;
 }
 
@@ -1425,34 +1684,40 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
        int err;
        struct pci_dev *pdev = adapter->pdev;
 
+       adapter->rx_csum = 1;
        adapter->ahw->mc_enabled = 0;
-       adapter->ahw->max_mc_count = 38;
+       adapter->ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
 
        netdev->netdev_ops         = &qlcnic_netdev_ops;
-       netdev->watchdog_timeo     = 5*HZ;
+       netdev->watchdog_timeo     = QLCNIC_WATCHDOG_TIMEOUTVALUE * HZ;
 
        qlcnic_change_mtu(netdev, netdev->mtu);
 
        SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
 
-       netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
-               NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
+       netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+                            NETIF_F_IPV6_CSUM | NETIF_F_GRO |
+                            NETIF_F_HW_VLAN_RX);
+       netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+                                 NETIF_F_IPV6_CSUM);
+
+       if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
+               netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+               netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
+       }
 
-       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
-               netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
-       if (pci_using_dac == 1)
-               netdev->hw_features |= NETIF_F_HIGHDMA;
+       if (pci_using_dac) {
+               netdev->features |= NETIF_F_HIGHDMA;
+               netdev->vlan_features |= NETIF_F_HIGHDMA;
+       }
 
-       netdev->vlan_features = netdev->hw_features;
+       if (qlcnic_vlan_tx_check(adapter))
+               netdev->features |= (NETIF_F_HW_VLAN_TX);
 
-       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
-               netdev->hw_features |= NETIF_F_HW_VLAN_TX;
        if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
-               netdev->hw_features |= NETIF_F_LRO;
-
-       netdev->features |= netdev->hw_features |
-               NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+               netdev->features |= NETIF_F_LRO;
 
+       netdev->hw_features = netdev->features;
        netdev->irq = adapter->msix_entries[0].vector;
 
        err = register_netdev(netdev);
@@ -1480,17 +1745,64 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, int *pci_using_dac)
        return 0;
 }
 
-static int
-qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count)
+void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter)
 {
-       adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry),
-                                       GFP_KERNEL);
+       int ring;
+       struct qlcnic_host_tx_ring *tx_ring;
 
-       if (adapter->msix_entries)
-               return 0;
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               if (tx_ring && tx_ring->cmd_buf_arr != NULL) {
+                       vfree(tx_ring->cmd_buf_arr);
+                       tx_ring->cmd_buf_arr = NULL;
+               }
+       }
+       if (adapter->tx_ring != NULL)
+               kfree(adapter->tx_ring);
+}
+
+int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
+                         struct net_device *netdev)
+{
+       int ring, size, vector, index;
+       struct qlcnic_host_tx_ring *tx_ring;
+       struct qlcnic_cmd_buffer *cmd_buf_arr;
 
-       dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n");
-       return -ENOMEM;
+       size = adapter->max_drv_tx_rings * sizeof(struct qlcnic_host_tx_ring);
+       tx_ring = kzalloc(size, GFP_KERNEL);
+       if (tx_ring == NULL) {
+               dev_err(&netdev->dev, "failed to allocate tx rings\n");
+               return -ENOMEM;
+       }
+       adapter->tx_ring = tx_ring;
+
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               tx_ring->num_desc = adapter->num_txd;
+               tx_ring->txq = netdev_get_tx_queue(netdev, ring);
+               cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
+               if (cmd_buf_arr == NULL) {
+                       dev_err(&netdev->dev,
+                               "failed to allocate cmd buffer ring\n");
+                       qlcnic_free_tx_rings(adapter);
+                       return -ENOMEM;
+               }
+               memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
+               tx_ring->cmd_buf_arr = cmd_buf_arr;
+       }
+
+       if (qlcnic_83xx_check(adapter)) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       tx_ring->adapter = adapter;
+                       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+                               index = adapter->max_sds_rings + ring;
+                               vector = adapter->msix_entries[index].vector;
+                               tx_ring->irq = vector;
+                       }
+               }
+       }
+       return 0;
 }
 
 static int
@@ -1498,8 +1810,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct net_device *netdev = NULL;
        struct qlcnic_adapter *adapter = NULL;
+       struct qlcnic_hardware_context *ahw;
        int err, pci_using_dac = -1;
-       uint8_t revision_id;
+       u32 capab2;
        char board_name[QLCNIC_MAX_BOARD_NAME_LEN];
 
        err = pci_enable_device(pdev);
@@ -1522,10 +1835,27 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_set_master(pdev);
        pci_enable_pcie_error_reporting(pdev);
 
+       ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL);
+       if (!ahw)
+               goto err_out_free_res;
+
+       if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE824X) {
+               ahw->hw_ops = &qlcnic_hw_ops;
+               ahw->reg_tbl = (u32 *)qlcnic_reg_tbl;
+       } else if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
+               qlcnic_83xx_register_map(ahw);
+       } else {
+               goto err_out_free_hw_res;
+       }
+
+       err = qlcnic_setup_pci_map(pdev, ahw);
+       if (err)
+               goto err_out_free_hw_res;
+
        netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
        if (!netdev) {
                err = -ENOMEM;
-               goto err_out_free_res;
+               goto err_out_iounmap;
        }
 
        SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -1533,15 +1863,25 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter = netdev_priv(netdev);
        adapter->netdev  = netdev;
        adapter->pdev    = pdev;
+       adapter->ahw = ahw;
+
+       adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic");
+       if (adapter->qlcnic_wq == NULL) {
+               dev_err(&pdev->dev, "Failed to create workqueue\n");
+               goto err_out_free_netdev;
+       }
 
        err = qlcnic_alloc_adapter_resources(adapter);
        if (err)
                goto err_out_free_netdev;
 
        adapter->dev_rst_time = jiffies;
-       revision_id = pdev->revision;
-       adapter->ahw->revision_id = revision_id;
-       adapter->mac_learn = qlcnic_mac_learn;
+       adapter->ahw->revision_id = pdev->revision;
+       if (qlcnic_mac_learn == FDB_MAC_LEARN)
+               adapter->fdb_mac_learn = true;
+       else if (qlcnic_mac_learn == DRV_MAC_LEARN)
+               adapter->drv_mac_learn = true;
+       adapter->max_drv_tx_rings = 1;
 
        rwlock_init(&adapter->ahw->crb_lock);
        mutex_init(&adapter->ahw->mem_lock);
@@ -1549,31 +1889,32 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        spin_lock_init(&adapter->tx_clean_lock);
        INIT_LIST_HEAD(&adapter->mac_list);
 
-       err = qlcnic_setup_pci_map(pdev, adapter->ahw);
-       if (err)
-               goto err_out_free_hw;
-       qlcnic_check_vf(adapter);
-
-       /* This will be reset for mezz cards  */
-       adapter->portnum = adapter->ahw->pci_func;
-
-       err = qlcnic_get_board_info(adapter);
-       if (err) {
-               dev_err(&pdev->dev, "Error getting board config info.\n");
-               goto err_out_iounmap;
-       }
-
-       err = qlcnic_setup_idc_param(adapter);
-       if (err)
-               goto err_out_iounmap;
+       if (qlcnic_82xx_check(adapter)) {
+               qlcnic_check_vf(adapter, ent);
+               adapter->portnum = adapter->ahw->pci_func;
+               err = qlcnic_start_firmware(adapter);
+               if (err) {
+                       dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
+                       goto err_out_free_hw;
+               }
 
-       adapter->flags |= QLCNIC_NEED_FLR;
+               err = qlcnic_setup_idc_param(adapter);
+               if (err)
+                       goto err_out_free_hw;
 
-       err = adapter->nic_ops->start_firmware(adapter);
-       if (err) {
-               dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
-                       "\t\tIf reboot doesn't help, try flashing the card\n");
-               goto err_out_maintenance_mode;
+               adapter->flags |= QLCNIC_NEED_FLR;
+       } else if (qlcnic_83xx_check(adapter)) {
+               qlcnic_83xx_check_vf(adapter, ent);
+               adapter->portnum = adapter->ahw->pci_func;
+               err = qlcnic_83xx_init(adapter);
+               if (err) {
+                       dev_err(&pdev->dev, "%s: failed\n", __func__);
+                       goto err_out_free_hw;
+               }
+       } else {
+               dev_err(&pdev->dev,
+                       "%s: failed. Please Reboot\n", __func__);
+               goto err_out_free_hw;
        }
 
        if (qlcnic_read_mac_addr(adapter))
@@ -1581,22 +1922,34 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        if (adapter->portnum == 0) {
                qlcnic_get_board_name(adapter, board_name);
+
                pr_info("%s: %s Board Chip rev 0x%x\n",
                        module_name(THIS_MODULE),
                        board_name, adapter->ahw->revision_id);
        }
+       err = qlcnic_setup_intr(adapter, 0);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to setup interrupt\n");
+               goto err_out_disable_msi;
+       }
 
-       qlcnic_clear_stats(adapter);
-
-       err = qlcnic_alloc_msix_entries(adapter, adapter->ahw->max_rx_ques);
-       if (err)
-               goto err_out_decr_ref;
-
-       qlcnic_setup_intr(adapter);
+       if (qlcnic_83xx_check(adapter)) {
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err)
+                       goto err_out_disable_msi;
+       }
 
        err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
        if (err)
-               goto err_out_disable_msi;
+               goto err_out_disable_mbx_intr;
+
+       if (qlcnic_82xx_check(adapter)) {
+               if (ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+                       capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+                       if (capab2 & QLCNIC_FW_CAPABILITY_2_OCBB)
+                               qlcnic_fw_cmd_set_drv_version(adapter);
+               }
+       }
 
        pci_set_drvdata(pdev, adapter);
 
@@ -1615,29 +1968,40 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        }
 
-       if (adapter->mac_learn)
+       if (qlcnic_get_act_pci_func(adapter))
+               goto err_out_disable_mbx_intr;
+
+       if (adapter->drv_mac_learn)
                qlcnic_alloc_lb_filters_mem(adapter);
 
-       qlcnic_create_diag_entries(adapter);
+       qlcnic_add_sysfs(adapter);
 
        return 0;
 
+err_out_disable_mbx_intr:
+       if (qlcnic_83xx_check(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+       }
+
 err_out_disable_msi:
        qlcnic_teardown_intr(adapter);
-       kfree(adapter->msix_entries);
-
-err_out_decr_ref:
+       qlcnic_cancel_idc_work(adapter);
        qlcnic_clr_all_drv_state(adapter, 0);
 
-err_out_iounmap:
-       qlcnic_cleanup_pci_map(adapter);
-
 err_out_free_hw:
        qlcnic_free_adapter_resources(adapter);
 
 err_out_free_netdev:
        free_netdev(netdev);
 
+err_out_iounmap:
+       qlcnic_cleanup_pci_map(adapter);
+
+err_out_free_hw_res:
+       kfree(ahw);
+
 err_out_free_res:
        pci_release_regions(pdev);
 
@@ -1645,24 +2009,13 @@ err_out_disable_pdev:
        pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
        return err;
-
-err_out_maintenance_mode:
-       netdev->netdev_ops = &qlcnic_netdev_failed_ops;
-       SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
-       err = register_netdev(netdev);
-       if (err) {
-               dev_err(&pdev->dev, "failed to register net device\n");
-               goto err_out_decr_ref;
-       }
-       pci_set_drvdata(pdev, adapter);
-       qlcnic_create_diag_entries(adapter);
-       return 0;
 }
 
 static void qlcnic_remove(struct pci_dev *pdev)
 {
        struct qlcnic_adapter *adapter;
        struct net_device *netdev;
+       struct qlcnic_hardware_context *ahw;
 
        adapter = pci_get_drvdata(pdev);
        if (adapter == NULL)
@@ -1670,10 +2023,17 @@ static void qlcnic_remove(struct pci_dev *pdev)
 
        netdev = adapter->netdev;
 
-       qlcnic_cancel_fw_work(adapter);
+       qlcnic_cancel_idc_work(adapter);
+       ahw = adapter->ahw;
 
        unregister_netdev(netdev);
 
+       if (qlcnic_83xx_check(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+       }
+
        qlcnic_detach(adapter);
 
        if (adapter->npars != NULL)
@@ -1689,9 +2049,8 @@ static void qlcnic_remove(struct pci_dev *pdev)
        qlcnic_free_lb_filters_mem(adapter);
 
        qlcnic_teardown_intr(adapter);
-       kfree(adapter->msix_entries);
 
-       qlcnic_remove_diag_entries(adapter);
+       qlcnic_remove_sysfs(adapter);
 
        qlcnic_cleanup_pci_map(adapter);
 
@@ -1702,7 +2061,12 @@ static void qlcnic_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
+       if (adapter->qlcnic_wq) {
+               destroy_workqueue(adapter->qlcnic_wq);
+               adapter->qlcnic_wq = NULL;
+       }
        qlcnic_free_adapter_resources(adapter);
+       kfree(ahw);
        free_netdev(netdev);
 }
 static int __qlcnic_shutdown(struct pci_dev *pdev)
@@ -1713,7 +2077,7 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
 
        netif_device_detach(netdev);
 
-       qlcnic_cancel_fw_work(adapter);
+       qlcnic_cancel_idc_work(adapter);
 
        if (netif_running(netdev))
                qlcnic_down(adapter, netdev);
@@ -1726,7 +2090,6 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
        retval = pci_save_state(pdev);
        if (retval)
                return retval;
-
        if (qlcnic_82xx_check(adapter)) {
                if (qlcnic_wol_supported(adapter)) {
                        pci_enable_wake(pdev, PCI_D3cold, 1);
@@ -1774,7 +2137,7 @@ qlcnic_resume(struct pci_dev *pdev)
        pci_set_master(pdev);
        pci_restore_state(pdev);
 
-       err = adapter->nic_ops->start_firmware(adapter);
+       err = qlcnic_start_firmware(adapter);
        if (err) {
                dev_err(&pdev->dev, "failed to start firmware\n");
                return err;
@@ -1797,14 +2160,8 @@ done:
 static int qlcnic_open(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
        int err;
 
-       if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
-               netdev_err(netdev, "Device in FAILED state\n");
-               return -EIO;
-       }
-
        netif_carrier_off(netdev);
 
        err = qlcnic_attach(adapter);
@@ -1832,6 +2189,11 @@ static int qlcnic_close(struct net_device *netdev)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
        __qlcnic_down(adapter, netdev);
+       if (qlcnic_83xx_check(adapter)) {
+               qlcnic_83xx_register_nic_idc_func(adapter, 0);
+               cancel_delayed_work_sync(&adapter->idc_aen_work);
+       }
+
        return 0;
 }
 
@@ -1839,21 +2201,37 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
 {
        void *head;
        int i;
+       struct net_device *netdev = adapter->netdev;
+       u32 filter_size = 0;
+       u16 act_pci_func = 0;
 
        if (adapter->fhash.fmax && adapter->fhash.fhead)
                return;
 
+       act_pci_func = adapter->ahw->act_pci_func;
        spin_lock_init(&adapter->mac_learn_lock);
 
-       head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
-                                                               GFP_KERNEL);
+       if (qlcnic_82xx_check(adapter)) {
+               filter_size = QLCNIC_LB_MAX_FILTERS;
+               adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE;
+       } else {
+               filter_size = QLC_83XX_LB_MAX_FILTERS;
+               adapter->fhash.fbucket_size = QLC_83XX_LB_BUCKET_SIZE;
+       }
+
+       head = kcalloc(adapter->fhash.fbucket_size,
+                      sizeof(struct hlist_head), GFP_ATOMIC);
+
        if (!head)
                return;
 
-       adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
+       adapter->fhash.fmax = (filter_size / act_pci_func);
        adapter->fhash.fhead = head;
 
-       for (i = 0; i < adapter->fhash.fmax; i++)
+       netdev_info(netdev, "active nic func = %d, mac filter size=%d\n",
+                   act_pci_func, adapter->fhash.fmax);
+
+       for (i = 0; i < adapter->fhash.fbucket_size; i++)
                INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
 }
 
@@ -1866,14 +2244,17 @@ static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
        adapter->fhash.fmax = 0;
 }
 
-static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
+int qlcnic_check_temp(struct qlcnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        u32 temp_state, temp_val, temp = 0;
        int rv = 0;
 
+       if (qlcnic_83xx_check(adapter))
+               temp = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP);
+
        if (qlcnic_82xx_check(adapter))
-               temp = QLCRD32(adapter, CRB_TEMP_STATE);
+               temp = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP);
 
        temp_state = qlcnic_get_temp_state(temp);
        temp_val = qlcnic_get_temp_val(temp);
@@ -1933,7 +2314,7 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
        return stats;
 }
 
-static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
 {
        u32 status;
 
@@ -2009,6 +2390,14 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data)
+{
+       struct qlcnic_host_tx_ring *tx_ring = data;
+
+       napi_schedule(&tx_ring->napi);
+       return IRQ_HANDLED;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void qlcnic_poll_controller(struct net_device *netdev)
 {
@@ -2035,7 +2424,7 @@ qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
        val |= encoding << 7;
        val |= (jiffies - adapter->dev_rst_time) << 8;
 
-       QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
        adapter->dev_rst_time = jiffies;
 }
 
@@ -2050,14 +2439,14 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
        if (qlcnic_api_lock(adapter))
                return -EIO;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
 
        if (state == QLCNIC_DEV_NEED_RESET)
                QLC_DEV_SET_RST_RDY(val, adapter->portnum);
        else if (state == QLCNIC_DEV_NEED_QUISCENT)
                QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
 
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
 
@@ -2072,9 +2461,9 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
        if (qlcnic_api_lock(adapter))
                return -EBUSY;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
        QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
 
@@ -2089,20 +2478,22 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
        if (qlcnic_api_lock(adapter))
                goto err;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+       val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
        QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
 
        if (failed) {
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                   QLCNIC_DEV_FAILED);
                dev_info(&adapter->pdev->dev,
                                "Device state set to Failed. Please Reboot\n");
        } else if (!(val & 0x11111111))
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                   QLCNIC_DEV_COLD);
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
        QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
 err:
@@ -2117,12 +2508,13 @@ static int
 qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 {
        int act, state, active_mask;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
+       act = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
 
        if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
-               active_mask = (~(1 << (adapter->ahw->pci_func * 4)));
+               active_mask = (~(1 << (ahw->pci_func * 4)));
                act = act & active_mask;
        }
 
@@ -2135,7 +2527,7 @@ qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 
 static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
 {
-       u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
+       u32 val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
 
        if (val != QLCNIC_DRV_IDC_VER) {
                dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
@@ -2159,19 +2551,21 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
        if (qlcnic_api_lock(adapter))
                return -1;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+       val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
        if (!(val & (1 << (portnum * 4)))) {
                QLC_DEV_SET_REF_CNT(val, portnum);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
        }
 
-       prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
        QLCDB(adapter, HW, "Device state = %u\n", prev_state);
 
        switch (prev_state) {
        case QLCNIC_DEV_COLD:
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                   QLCNIC_DEV_INITIALIZING);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_IDC_VER,
+                                   QLCNIC_DRV_IDC_VER);
                qlcnic_idc_debug_info(adapter, 0);
                qlcnic_api_unlock(adapter);
                return 1;
@@ -2182,15 +2576,15 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
                return ret;
 
        case QLCNIC_DEV_NEED_RESET:
-               val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+               val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
                QLC_DEV_SET_RST_RDY(val, portnum);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
                break;
 
        case QLCNIC_DEV_NEED_QUISCENT:
-               val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+               val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
                QLC_DEV_SET_QSCNT_RDY(val, portnum);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
                break;
 
        case QLCNIC_DEV_FAILED:
@@ -2207,7 +2601,7 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
 
        do {
                msleep(1000);
-               prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+               prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 
                if (prev_state == QLCNIC_DEV_QUISCENT)
                        continue;
@@ -2222,9 +2616,9 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
        if (qlcnic_api_lock(adapter))
                return -1;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
        QLC_DEV_CLR_RST_QSCNT(val, portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        ret = qlcnic_check_idc_ver(adapter);
        qlcnic_api_unlock(adapter);
@@ -2243,7 +2637,7 @@ qlcnic_fwinit_work(struct work_struct *work)
        if (qlcnic_api_lock(adapter))
                goto err_ret;
 
-       dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
        if (dev_state == QLCNIC_DEV_QUISCENT ||
            dev_state == QLCNIC_DEV_NEED_QUISCENT) {
                qlcnic_api_unlock(adapter);
@@ -2272,17 +2666,19 @@ qlcnic_fwinit_work(struct work_struct *work)
 
        if (!qlcnic_check_drv_state(adapter)) {
 skip_ack_check:
-               dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+               dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 
                if (dev_state == QLCNIC_DEV_NEED_RESET) {
-                       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
-                                               QLCNIC_DEV_INITIALIZING);
+                       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                           QLCNIC_DEV_INITIALIZING);
                        set_bit(__QLCNIC_START_FW, &adapter->state);
                        QLCDB(adapter, DRV, "Restarting fw\n");
                        qlcnic_idc_debug_info(adapter, 0);
-                       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+                       val = QLC_SHARED_REG_RD32(adapter,
+                                                 QLCNIC_CRB_DRV_STATE);
                        QLC_DEV_SET_RST_RDY(val, adapter->portnum);
-                       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+                       QLC_SHARED_REG_WR32(adapter,
+                                           QLCNIC_CRB_DRV_STATE, val);
                }
 
                qlcnic_api_unlock(adapter);
@@ -2308,12 +2704,12 @@ skip_ack_check:
        qlcnic_api_unlock(adapter);
 
 wait_npar:
-       dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
        QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
 
        switch (dev_state) {
        case QLCNIC_DEV_READY:
-               if (!adapter->nic_ops->start_firmware(adapter)) {
+               if (!qlcnic_start_firmware(adapter)) {
                        qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
                        adapter->fw_wait_cnt = 0;
                        return;
@@ -2350,7 +2746,7 @@ qlcnic_detach_work(struct work_struct *work)
        } else
                qlcnic_down(adapter, netdev);
 
-       status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+       status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
 
        if (status & QLCNIC_RCODE_FATAL_ERROR) {
                dev_err(&adapter->pdev->dev,
@@ -2401,19 +2797,18 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
 {
        u32 state;
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
        if (state == QLCNIC_DEV_NPAR_NON_OPER)
                return;
 
        if (qlcnic_api_lock(adapter))
                return;
-       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+                           QLCNIC_DEV_NPAR_NON_OPER);
        qlcnic_api_unlock(adapter);
 }
 
-/*Transit to RESET state from READY state only */
-void
-qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
 {
        u32 state, xg_val = 0, gb_val = 0;
 
@@ -2428,25 +2823,22 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
        dev_info(&adapter->pdev->dev, "Pause control frames disabled"
                                " on all ports\n");
        adapter->need_fw_reset = 1;
+
        if (qlcnic_api_lock(adapter))
                return;
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-       if (state  == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
-               netdev_err(adapter->netdev,
-                               "Device is in FAILED state, Please Reboot\n");
-               qlcnic_api_unlock(adapter);
-               return;
-       }
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 
        if (state == QLCNIC_DEV_READY) {
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                   QLCNIC_DEV_NEED_RESET);
                adapter->flags |= QLCNIC_FW_RESET_OWNER;
                QLCDB(adapter, DRV, "NEED_RESET state set\n");
                qlcnic_idc_debug_info(adapter, 0);
        }
 
-       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+                           QLCNIC_DEV_NPAR_NON_OPER);
        qlcnic_api_unlock(adapter);
 }
 
@@ -2457,34 +2849,22 @@ qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
        if (qlcnic_api_lock(adapter))
                return;
 
-       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+                           QLCNIC_DEV_NPAR_OPER);
        QLCDB(adapter, DRV, "NPAR operational state set\n");
 
        qlcnic_api_unlock(adapter);
 }
 
-static void
-qlcnic_schedule_work(struct qlcnic_adapter *adapter,
-               work_func_t func, int delay)
+void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+                         work_func_t func, int delay)
 {
        if (test_bit(__QLCNIC_AER, &adapter->state))
                return;
 
        INIT_DELAYED_WORK(&adapter->fw_work, func);
-       queue_delayed_work(qlcnic_wq, &adapter->fw_work,
-                                       round_jiffies_relative(delay));
-}
-
-static void
-qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
-{
-       while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
-               msleep(10);
-
-       if (!adapter->fw_work.work.func)
-               return;
-
-       cancel_delayed_work_sync(&adapter->fw_work);
+       queue_delayed_work(adapter->qlcnic_wq, &adapter->fw_work,
+                          round_jiffies_relative(delay));
 }
 
 static void
@@ -2496,7 +2876,8 @@ qlcnic_attach_work(struct work_struct *work)
        u32 npar_state;
 
        if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
-               npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+               npar_state = QLC_SHARED_REG_RD32(adapter,
+                                                QLCNIC_CRB_DEV_NPAR_STATE);
                if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
                        qlcnic_clr_all_drv_state(adapter, 0);
                else if (npar_state != QLCNIC_DEV_NPAR_OPER)
@@ -2536,16 +2917,16 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
                goto detach;
 
        if (adapter->need_fw_reset)
-               qlcnic_dev_request_reset(adapter);
+               qlcnic_dev_request_reset(adapter, 0);
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
        if (state == QLCNIC_DEV_NEED_RESET) {
                qlcnic_set_npar_non_operational(adapter);
                adapter->need_fw_reset = 1;
        } else if (state == QLCNIC_DEV_NEED_QUISCENT)
                goto detach;
 
-       heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+       heartbeat = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
        if (heartbeat != adapter->heartbeat) {
                adapter->heartbeat = heartbeat;
                adapter->fw_fail_cnt = 0;
@@ -2565,25 +2946,25 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
 
        adapter->flags |= QLCNIC_FW_HANG;
 
-       qlcnic_dev_request_reset(adapter);
+       qlcnic_dev_request_reset(adapter, 0);
 
        if (qlcnic_auto_fw_reset)
                clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
 
        dev_err(&adapter->pdev->dev, "firmware hang detected\n");
+       peg_status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
        dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
                        "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
                        "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
                        "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
                        "PEG_NET_4_PC: 0x%x\n",
-                       QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1),
-                       QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS2),
+                       peg_status,
+                       QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2),
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
-       peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
        if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
                dev_err(&adapter->pdev->dev,
                        "Firmware aborted with error code 0x00006700. "
@@ -2667,17 +3048,37 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
        if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
                adapter->need_fw_reset = 1;
                set_bit(__QLCNIC_START_FW, &adapter->state);
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+               QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                   QLCNIC_DEV_INITIALIZING);
                QLCDB(adapter, DRV, "Restarting fw\n");
        }
        qlcnic_api_unlock(adapter);
 
-       err = adapter->nic_ops->start_firmware(adapter);
+       err = qlcnic_start_firmware(adapter);
        if (err)
                return err;
 
        qlcnic_clr_drv_state(adapter);
-       qlcnic_setup_intr(adapter);
+       kfree(adapter->msix_entries);
+       adapter->msix_entries = NULL;
+       err = qlcnic_setup_intr(adapter, 0);
+
+       if (err) {
+               kfree(adapter->msix_entries);
+               netdev_err(netdev, "failed to setup interrupt\n");
+               return err;
+       }
+
+       if (qlcnic_83xx_check(adapter)) {
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "failed to setup mbx interrupt\n");
+                       qlcnic_clr_all_drv_state(adapter, 1);
+                       clear_bit(__QLCNIC_AER, &adapter->state);
+                       goto done;
+               }
+       }
 
        if (netif_running(netdev)) {
                err = qlcnic_attach(adapter);
@@ -2719,6 +3120,12 @@ static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
        if (netif_running(netdev))
                qlcnic_down(adapter, netdev);
 
+       if (qlcnic_83xx_check(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+       }
+
        qlcnic_detach(adapter);
        qlcnic_teardown_intr(adapter);
 
@@ -2738,12 +3145,13 @@ static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
 
 static void qlcnic_io_resume(struct pci_dev *pdev)
 {
+       u32 state;
        struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
 
        pci_cleanup_aer_uncorrect_error_status(pdev);
-
-       if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
-           test_and_clear_bit(__QLCNIC_AER, &adapter->state))
+       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_READY && test_and_clear_bit(__QLCNIC_AER,
+                                                           &adapter->state))
                qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
                                                FW_POLL_DELAY);
 }
@@ -2776,39 +3184,59 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
        return err;
 }
 
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
+int qlcnic_validate_max_rss(u8 max_hw, u8 val)
 {
-       if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
-               netdev_info(netdev, "no msix or msi support, hence no rss\n");
-               return -EINVAL;
+       u32 max_allowed;
+
+       if (max_hw > QLC_MAX_SDS_RINGS) {
+               max_hw = QLC_MAX_SDS_RINGS;
+               pr_info("max rss reset to %d\n", QLC_MAX_SDS_RINGS);
        }
 
-       if ((val > max_hw) || (val <  2) || !is_power_of_2(val)) {
-               netdev_info(netdev, "rss_ring valid range [2 - %x] in "
-                       " powers of 2\n", max_hw);
+       max_allowed = rounddown_pow_of_two(min_t(int, max_hw,
+                                                num_online_cpus()));
+       if ((val > max_allowed) || (val < 2) || !is_power_of_2(val)) {
+               pr_info("rss_ring valid range [2 - %x] in powers of 2\n",
+                       max_allowed);
                return -EINVAL;
        }
        return 0;
-
 }
 
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
 {
+       int err;
        struct net_device *netdev = adapter->netdev;
-       int err = 0;
 
-       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+       if (test_bit(__QLCNIC_RESETTING, &adapter->state))
                return -EBUSY;
 
        netif_device_detach(netdev);
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
+
+       if (qlcnic_82xx_check(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+       }
+
        qlcnic_detach(adapter);
        qlcnic_teardown_intr(adapter);
+       err = qlcnic_setup_intr(adapter, data);
+       if (err) {
+               kfree(adapter->msix_entries);
+               netdev_err(netdev, "failed to setup interrupt\n");
+               return err;
+       }
 
-       if (qlcnic_enable_msix(adapter, data)) {
-               netdev_info(netdev, "failed setting max_rss; rss disabled\n");
-               qlcnic_enable_msi_legacy(adapter);
+       if (qlcnic_83xx_check(adapter)) {
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "failed to setup mbx interrupt\n");
+                       goto done;
+               }
        }
 
        if (netif_running(netdev)) {
@@ -2820,6 +3248,7 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
                        goto done;
                qlcnic_restore_indev_addr(netdev, NETDEV_UP);
        }
+       err = len;
  done:
        netif_device_attach(netdev);
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -2858,8 +3287,7 @@ qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
        in_dev_put(indev);
 }
 
-static void
-qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
+void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct net_device *dev;
@@ -2867,12 +3295,14 @@ qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
 
        qlcnic_config_indev_addr(adapter, netdev, event);
 
+       rcu_read_lock();
        for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
                dev = __vlan_find_dev_deep(netdev, vid);
                if (!dev)
                        continue;
                qlcnic_config_indev_addr(adapter, dev, event);
        }
+       rcu_read_unlock();
 }
 
 static int qlcnic_netdev_event(struct notifier_block *this,
@@ -2940,9 +3370,11 @@ recheck:
        switch (event) {
        case NETDEV_UP:
                qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
+
                break;
        case NETDEV_DOWN:
                qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
+
                break;
        default:
                break;
@@ -2960,8 +3392,7 @@ static struct notifier_block qlcnic_inetaddr_cb = {
        .notifier_call = qlcnic_inetaddr_event,
 };
 #else
-static void
-qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
+void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
 { }
 #endif
 static struct pci_error_handlers qlcnic_err_handler = {
@@ -2990,12 +3421,6 @@ static int __init qlcnic_init_module(void)
 
        printk(KERN_INFO "%s\n", qlcnic_driver_string);
 
-       qlcnic_wq = create_singlethread_workqueue("qlcnic");
-       if (qlcnic_wq == NULL) {
-               printk(KERN_ERR "qlcnic: cannot create workqueue\n");
-               return -ENOMEM;
-       }
-
 #ifdef CONFIG_INET
        register_netdevice_notifier(&qlcnic_netdev_cb);
        register_inetaddr_notifier(&qlcnic_inetaddr_cb);
@@ -3007,7 +3432,6 @@ static int __init qlcnic_init_module(void)
                unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
                unregister_netdevice_notifier(&qlcnic_netdev_cb);
 #endif
-               destroy_workqueue(qlcnic_wq);
        }
 
        return ret;
@@ -3017,14 +3441,12 @@ module_init(qlcnic_init_module);
 
 static void __exit qlcnic_exit_module(void)
 {
-
        pci_unregister_driver(&qlcnic_driver);
 
 #ifdef CONFIG_INET
        unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
        unregister_netdevice_notifier(&qlcnic_netdev_cb);
 #endif
-       destroy_workqueue(qlcnic_wq);
 }
 
 module_exit(qlcnic_exit_module);
index 0b8d8625834cc440a42b94b41aac5e6e2a76c948..6281cbd1a654844a0d694f1c118f04f0bf15ce0f 100644 (file)
@@ -1,8 +1,19 @@
+
 #include "qlcnic.h"
 #include "qlcnic_hdr.h"
+#include "qlcnic_83xx_hw.h"
+#include "qlcnic_hw.h"
 
 #include <net/ip.h>
 
+#define QLC_83XX_MINIDUMP_FLASH                0x520000
+#define QLC_83XX_OCM_INDEX                     3
+#define QLC_83XX_PCI_INDEX                     0
+
+static const u32 qlcnic_ms_read_data[] = {
+       0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC
+};
+
 #define QLCNIC_DUMP_WCRB       BIT_0
 #define QLCNIC_DUMP_RWCRB      BIT_1
 #define QLCNIC_DUMP_ANDCRB     BIT_2
@@ -102,16 +113,55 @@ struct __queue {
        u8      rsvd3[2];
 } __packed;
 
+struct __pollrd {
+       u32     sel_addr;
+       u32     read_addr;
+       u32     sel_val;
+       u16     sel_val_stride;
+       u16     no_ops;
+       u32     poll_wait;
+       u32     poll_mask;
+       u32     data_size;
+       u8      rsvd[4];
+} __packed;
+
+struct __mux2 {
+       u32     sel_addr1;
+       u32     sel_addr2;
+       u32     sel_val1;
+       u32     sel_val2;
+       u32     no_ops;
+       u32     sel_val_mask;
+       u32     read_addr;
+       u8      sel_val_stride;
+       u8      data_size;
+       u8      rsvd[2];
+} __packed;
+
+struct __pollrdmwr {
+       u32     addr1;
+       u32     addr2;
+       u32     val1;
+       u32     val2;
+       u32     poll_wait;
+       u32     poll_mask;
+       u32     mod_mask;
+       u32     data_size;
+} __packed;
+
 struct qlcnic_dump_entry {
        struct qlcnic_common_entry_hdr hdr;
        union {
-               struct __crb    crb;
-               struct __cache  cache;
-               struct __ocm    ocm;
-               struct __mem    mem;
-               struct __mux    mux;
-               struct __queue  que;
-               struct __ctrl   ctrl;
+               struct __crb            crb;
+               struct __cache          cache;
+               struct __ocm            ocm;
+               struct __mem            mem;
+               struct __mux            mux;
+               struct __queue          que;
+               struct __ctrl           ctrl;
+               struct __pollrdmwr      pollrdmwr;
+               struct __mux2           mux2;
+               struct __pollrd         pollrd;
        } region;
 } __packed;
 
@@ -131,6 +181,9 @@ enum qlcnic_minidump_opcode {
        QLCNIC_DUMP_L2_ITAG     = 22,
        QLCNIC_DUMP_L2_DATA     = 23,
        QLCNIC_DUMP_L2_INST     = 24,
+       QLCNIC_DUMP_POLL_RD     = 35,
+       QLCNIC_READ_MUX2        = 36,
+       QLCNIC_READ_POLLRDMWR   = 37,
        QLCNIC_DUMP_READ_ROM    = 71,
        QLCNIC_DUMP_READ_MEM    = 72,
        QLCNIC_DUMP_READ_CTRL   = 98,
@@ -144,46 +197,17 @@ struct qlcnic_dump_operations {
                       __le32 *);
 };
 
-static void qlcnic_read_dump_reg(u32 addr, void __iomem *bar0, u32 *data)
-{
-       u32 dest;
-       void __iomem *window_reg;
-
-       dest = addr & 0xFFFF0000;
-       window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
-       writel(dest, window_reg);
-       readl(window_reg);
-       window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
-       *data = readl(window_reg);
-}
-
-static void qlcnic_write_dump_reg(u32 addr, void __iomem *bar0, u32 data)
-{
-       u32 dest;
-       void __iomem *window_reg;
-
-       dest = addr & 0xFFFF0000;
-       window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
-       writel(dest, window_reg);
-       readl(window_reg);
-       window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
-       writel(data, window_reg);
-       readl(window_reg);
-}
-
-/* FW dump related functions */
 static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
                           struct qlcnic_dump_entry *entry, __le32 *buffer)
 {
        int i;
        u32 addr, data;
        struct __crb *crb = &entry->region.crb;
-       void __iomem *base = adapter->ahw->pci_base0;
 
        addr = crb->addr;
 
        for (i = 0; i < crb->no_ops; i++) {
-               qlcnic_read_dump_reg(addr, base, &data);
+               data = qlcnic_ind_rd(adapter, addr);
                *buffer++ = cpu_to_le32(addr);
                *buffer++ = cpu_to_le32(data);
                addr += crb->stride;
@@ -195,7 +219,6 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
                            struct qlcnic_dump_entry *entry, __le32 *buffer)
 {
        int i, k, timeout = 0;
-       void __iomem *base = adapter->ahw->pci_base0;
        u32 addr, data;
        u8 no_ops;
        struct __ctrl *ctr = &entry->region.ctrl;
@@ -211,28 +234,28 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
                                continue;
                        switch (1 << k) {
                        case QLCNIC_DUMP_WCRB:
-                               qlcnic_write_dump_reg(addr, base, ctr->val1);
+                               qlcnic_ind_wr(adapter, addr, ctr->val1);
                                break;
                        case QLCNIC_DUMP_RWCRB:
-                               qlcnic_read_dump_reg(addr, base, &data);
-                               qlcnic_write_dump_reg(addr, base, data);
+                               data = qlcnic_ind_rd(adapter, addr);
+                               qlcnic_ind_wr(adapter, addr, data);
                                break;
                        case QLCNIC_DUMP_ANDCRB:
-                               qlcnic_read_dump_reg(addr, base, &data);
-                               qlcnic_write_dump_reg(addr, base,
-                                                     data & ctr->val2);
+                               data = qlcnic_ind_rd(adapter, addr);
+                               qlcnic_ind_wr(adapter, addr,
+                                             (data & ctr->val2));
                                break;
                        case QLCNIC_DUMP_ORCRB:
-                               qlcnic_read_dump_reg(addr, base, &data);
-                               qlcnic_write_dump_reg(addr, base,
-                                                     data | ctr->val3);
+                               data = qlcnic_ind_rd(adapter, addr);
+                               qlcnic_ind_wr(adapter, addr,
+                                             (data | ctr->val3));
                                break;
                        case QLCNIC_DUMP_POLLCRB:
                                while (timeout <= ctr->timeout) {
-                                       qlcnic_read_dump_reg(addr, base, &data);
+                                       data = qlcnic_ind_rd(adapter, addr);
                                        if ((data & ctr->val2) == ctr->val1)
                                                break;
-                                       msleep(1);
+                                       usleep_range(1000, 2000);
                                        timeout++;
                                }
                                if (timeout > ctr->timeout) {
@@ -244,7 +267,7 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
                        case QLCNIC_DUMP_RD_SAVE:
                                if (ctr->index_a)
                                        addr = t_hdr->saved_state[ctr->index_a];
-                               qlcnic_read_dump_reg(addr, base, &data);
+                               data = qlcnic_ind_rd(adapter, addr);
                                t_hdr->saved_state[ctr->index_v] = data;
                                break;
                        case QLCNIC_DUMP_WRT_SAVED:
@@ -254,7 +277,7 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
                                        data = ctr->val1;
                                if (ctr->index_a)
                                        addr = t_hdr->saved_state[ctr->index_a];
-                               qlcnic_write_dump_reg(addr, base, data);
+                               qlcnic_ind_wr(adapter, addr, data);
                                break;
                        case QLCNIC_DUMP_MOD_SAVE_ST:
                                data = t_hdr->saved_state[ctr->index_v];
@@ -283,12 +306,11 @@ static u32 qlcnic_dump_mux(struct qlcnic_adapter *adapter,
        int loop;
        u32 val, data = 0;
        struct __mux *mux = &entry->region.mux;
-       void __iomem *base = adapter->ahw->pci_base0;
 
        val = mux->val;
        for (loop = 0; loop < mux->no_ops; loop++) {
-               qlcnic_write_dump_reg(mux->addr, base, val);
-               qlcnic_read_dump_reg(mux->read_addr, base, &data);
+               qlcnic_ind_wr(adapter, mux->addr, val);
+               data = qlcnic_ind_rd(adapter, mux->read_addr);
                *buffer++ = cpu_to_le32(val);
                *buffer++ = cpu_to_le32(data);
                val += mux->val_stride;
@@ -301,17 +323,16 @@ static u32 qlcnic_dump_que(struct qlcnic_adapter *adapter,
 {
        int i, loop;
        u32 cnt, addr, data, que_id = 0;
-       void __iomem *base = adapter->ahw->pci_base0;
        struct __queue *que = &entry->region.que;
 
        addr = que->read_addr;
        cnt = que->read_addr_cnt;
 
        for (loop = 0; loop < que->no_ops; loop++) {
-               qlcnic_write_dump_reg(que->sel_addr, base, que_id);
+               qlcnic_ind_wr(adapter, que->sel_addr, que_id);
                addr = que->read_addr;
                for (i = 0; i < cnt; i++) {
-                       qlcnic_read_dump_reg(addr, base, &data);
+                       data = qlcnic_ind_rd(adapter, addr);
                        *buffer++ = cpu_to_le32(data);
                        addr += que->read_addr_stride;
                }
@@ -343,27 +364,27 @@ static u32 qlcnic_read_rom(struct qlcnic_adapter *adapter,
        int i, count = 0;
        u32 fl_addr, size, val, lck_val, addr;
        struct __mem *rom = &entry->region.mem;
-       void __iomem *base = adapter->ahw->pci_base0;
 
        fl_addr = rom->addr;
-       size = rom->size/4;
+       size = rom->size / 4;
 lock_try:
-       lck_val = readl(base + QLCNIC_FLASH_SEM2_LK);
+       lck_val = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
        if (!lck_val && count < MAX_CTL_CHECK) {
-               msleep(10);
+               usleep_range(10000, 11000);
                count++;
                goto lock_try;
        }
-       writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID));
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
+                           adapter->ahw->pci_func);
        for (i = 0; i < size; i++) {
                addr = fl_addr & 0xFFFF0000;
-               qlcnic_write_dump_reg(FLASH_ROM_WINDOW, base, addr);
+               qlcnic_ind_wr(adapter, FLASH_ROM_WINDOW, addr);
                addr = LSW(fl_addr) + FLASH_ROM_DATA;
-               qlcnic_read_dump_reg(addr, base, &val);
+               val = qlcnic_ind_rd(adapter, addr);
                fl_addr += 4;
                *buffer++ = cpu_to_le32(val);
        }
-       readl(base + QLCNIC_FLASH_SEM2_ULK);
+       QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
        return rom->size;
 }
 
@@ -372,18 +393,17 @@ static u32 qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
 {
        int i;
        u32 cnt, val, data, addr;
-       void __iomem *base = adapter->ahw->pci_base0;
        struct __cache *l1 = &entry->region.cache;
 
        val = l1->init_tag_val;
 
        for (i = 0; i < l1->no_ops; i++) {
-               qlcnic_write_dump_reg(l1->addr, base, val);
-               qlcnic_write_dump_reg(l1->ctrl_addr, base, LSW(l1->ctrl_val));
+               qlcnic_ind_wr(adapter, l1->addr, val);
+               qlcnic_ind_wr(adapter, l1->ctrl_addr, LSW(l1->ctrl_val));
                addr = l1->read_addr;
                cnt = l1->read_addr_num;
                while (cnt) {
-                       qlcnic_read_dump_reg(addr, base, &data);
+                       data = qlcnic_ind_rd(adapter, addr);
                        *buffer++ = cpu_to_le32(data);
                        addr += l1->read_addr_stride;
                        cnt--;
@@ -399,7 +419,6 @@ static u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
        int i;
        u32 cnt, val, data, addr;
        u8 poll_mask, poll_to, time_out = 0;
-       void __iomem *base = adapter->ahw->pci_base0;
        struct __cache *l2 = &entry->region.cache;
 
        val = l2->init_tag_val;
@@ -407,17 +426,17 @@ static u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
        poll_to = MSB(MSW(l2->ctrl_val));
 
        for (i = 0; i < l2->no_ops; i++) {
-               qlcnic_write_dump_reg(l2->addr, base, val);
+               qlcnic_ind_wr(adapter, l2->addr, val);
                if (LSW(l2->ctrl_val))
-                       qlcnic_write_dump_reg(l2->ctrl_addr, base,
-                                             LSW(l2->ctrl_val));
+                       qlcnic_ind_wr(adapter, l2->ctrl_addr,
+                                     LSW(l2->ctrl_val));
                if (!poll_mask)
                        goto skip_poll;
                do {
-                       qlcnic_read_dump_reg(l2->ctrl_addr, base, &data);
+                       data = qlcnic_ind_rd(adapter, l2->ctrl_addr);
                        if (!(data & poll_mask))
                                break;
-                       msleep(1);
+                       usleep_range(1000, 2000);
                        time_out++;
                } while (time_out <= poll_to);
 
@@ -431,7 +450,7 @@ skip_poll:
                addr = l2->read_addr;
                cnt = l2->read_addr_num;
                while (cnt) {
-                       qlcnic_read_dump_reg(addr, base, &data);
+                       data = qlcnic_ind_rd(adapter, addr);
                        *buffer++ = cpu_to_le32(data);
                        addr += l2->read_addr_stride;
                        cnt--;
@@ -447,7 +466,6 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
        u32 addr, data, test, ret = 0;
        int i, reg_read;
        struct __mem *mem = &entry->region.mem;
-       void __iomem *base = adapter->ahw->pci_base0;
 
        reg_read = mem->size;
        addr = mem->addr;
@@ -462,13 +480,12 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
        mutex_lock(&adapter->ahw->mem_lock);
 
        while (reg_read != 0) {
-               qlcnic_write_dump_reg(MIU_TEST_ADDR_LO, base, addr);
-               qlcnic_write_dump_reg(MIU_TEST_ADDR_HI, base, 0);
-               qlcnic_write_dump_reg(MIU_TEST_CTR, base,
-                                     TA_CTL_ENABLE | TA_CTL_START);
+               qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);
+               qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);
+               qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_START_ENABLE);
 
                for (i = 0; i < MAX_CTL_CHECK; i++) {
-                       qlcnic_read_dump_reg(MIU_TEST_CTR, base, &test);
+                       test = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);
                        if (!(test & TA_CTL_BUSY))
                                break;
                }
@@ -481,8 +498,7 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
                        }
                }
                for (i = 0; i < 4; i++) {
-                       qlcnic_read_dump_reg(MIU_TEST_READ_DATA[i], base,
-                                            &data);
+                       data = qlcnic_ind_rd(adapter, qlcnic_ms_read_data[i]);
                        *buffer++ = cpu_to_le32(data);
                }
                addr += 16;
@@ -501,48 +517,388 @@ static u32 qlcnic_dump_nop(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-static const struct qlcnic_dump_operations fw_dump_ops[] = {
-       { QLCNIC_DUMP_NOP, qlcnic_dump_nop },
-       { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
-       { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
-       { QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
-       { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
-       { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
-       { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
-       { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
-       { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
-       { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
-       { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
-       { QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
-};
-
-/* Walk the template and collect dump for each entry in the dump template */
-static int
-qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
-                       u32 size)
+static int qlcnic_valid_dump_entry(struct device *dev,
+                                  struct qlcnic_dump_entry *entry, u32 size)
 {
        int ret = 1;
        if (size != entry->hdr.cap_size) {
-               dev_info(dev,
-                        "Invalid dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
-               entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
-               dev_info(dev, "Aborting further dump capture\n");
+               dev_err(dev,
+                       "Invalid entry, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+                       entry->hdr.type, entry->hdr.mask, size,
+                       entry->hdr.cap_size);
                ret = 0;
        }
        return ret;
 }
 
+static u32 qlcnic_read_pollrdmwr(struct qlcnic_adapter *adapter,
+                                struct qlcnic_dump_entry *entry,
+                                __le32 *buffer)
+{
+       struct __pollrdmwr *poll = &entry->region.pollrdmwr;
+       u32 data, wait_count, poll_wait, temp;
+
+       poll_wait = poll->poll_wait;
+
+       qlcnic_ind_wr(adapter, poll->addr1, poll->val1);
+       wait_count = 0;
+
+       while (wait_count < poll_wait) {
+               data = qlcnic_ind_rd(adapter, poll->addr1);
+               if ((data & poll->poll_mask) != 0)
+                       break;
+               wait_count++;
+       }
+
+       if (wait_count == poll_wait) {
+               dev_err(&adapter->pdev->dev,
+                       "Timeout exceeded in %s, aborting dump\n",
+                       __func__);
+               return 0;
+       }
+
+       data = qlcnic_ind_rd(adapter, poll->addr2) & poll->mod_mask;
+       qlcnic_ind_wr(adapter, poll->addr2, data);
+       qlcnic_ind_wr(adapter, poll->addr1, poll->val2);
+       wait_count = 0;
+
+       while (wait_count < poll_wait) {
+               temp = qlcnic_ind_rd(adapter, poll->addr1);
+               if ((temp & poll->poll_mask) != 0)
+                       break;
+               wait_count++;
+       }
+
+       *buffer++ = cpu_to_le32(poll->addr2);
+       *buffer++ = cpu_to_le32(data);
+
+       return 2 * sizeof(u32);
+
+}
+
+static u32 qlcnic_read_pollrd(struct qlcnic_adapter *adapter,
+                             struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+       struct __pollrd *pollrd = &entry->region.pollrd;
+       u32 data, wait_count, poll_wait, sel_val;
+       int i;
+
+       poll_wait = pollrd->poll_wait;
+       sel_val = pollrd->sel_val;
+
+       for (i = 0; i < pollrd->no_ops; i++) {
+               qlcnic_ind_wr(adapter, pollrd->sel_addr, sel_val);
+               wait_count = 0;
+               while (wait_count < poll_wait) {
+                       data = qlcnic_ind_rd(adapter, pollrd->sel_addr);
+                       if ((data & pollrd->poll_mask) != 0)
+                               break;
+                       wait_count++;
+               }
+
+               if (wait_count == poll_wait) {
+                       dev_err(&adapter->pdev->dev,
+                               "Timeout exceeded in %s, aborting dump\n",
+                               __func__);
+                       return 0;
+               }
+
+               data = qlcnic_ind_rd(adapter, pollrd->read_addr);
+               *buffer++ = cpu_to_le32(sel_val);
+               *buffer++ = cpu_to_le32(data);
+               sel_val += pollrd->sel_val_stride;
+       }
+       return pollrd->no_ops * (2 * sizeof(u32));
+}
+
+static u32 qlcnic_read_mux2(struct qlcnic_adapter *adapter,
+                           struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+       struct __mux2 *mux2 = &entry->region.mux2;
+       u32 data;
+       u32 t_sel_val, sel_val1, sel_val2;
+       int i;
+
+       sel_val1 = mux2->sel_val1;
+       sel_val2 = mux2->sel_val2;
+
+       for (i = 0; i < mux2->no_ops; i++) {
+               qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val1);
+               t_sel_val = sel_val1 & mux2->sel_val_mask;
+               qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+               data = qlcnic_ind_rd(adapter, mux2->read_addr);
+               *buffer++ = cpu_to_le32(t_sel_val);
+               *buffer++ = cpu_to_le32(data);
+               qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val2);
+               t_sel_val = sel_val2 & mux2->sel_val_mask;
+               qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+               data = qlcnic_ind_rd(adapter, mux2->read_addr);
+               *buffer++ = cpu_to_le32(t_sel_val);
+               *buffer++ = cpu_to_le32(data);
+               sel_val1 += mux2->sel_val_stride;
+               sel_val2 += mux2->sel_val_stride;
+       }
+
+       return mux2->no_ops * (4 * sizeof(u32));
+}
+
+static u32 qlcnic_83xx_dump_rom(struct qlcnic_adapter *adapter,
+                               struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+       u32 fl_addr, size;
+       struct __mem *rom = &entry->region.mem;
+
+       fl_addr = rom->addr;
+       size = rom->size / 4;
+
+       if (!qlcnic_83xx_lockless_flash_read32(adapter, fl_addr,
+                                              (u8 *)buffer, size))
+               return rom->size;
+
+       return 0;
+}
+
+static const struct qlcnic_dump_operations qlcnic_fw_dump_ops[] = {
+       {QLCNIC_DUMP_NOP, qlcnic_dump_nop},
+       {QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
+       {QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
+       {QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
+       {QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom},
+       {QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
+       {QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
+       {QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_READ_ROM, qlcnic_read_rom},
+       {QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
+       {QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
+       {QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
+       {QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
+};
+
+static const struct qlcnic_dump_operations qlcnic_83xx_fw_dump_ops[] = {
+       {QLCNIC_DUMP_NOP, qlcnic_dump_nop},
+       {QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
+       {QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
+       {QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
+       {QLCNIC_DUMP_BRD_CONFIG, qlcnic_83xx_dump_rom},
+       {QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
+       {QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
+       {QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
+       {QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
+       {QLCNIC_DUMP_POLL_RD, qlcnic_read_pollrd},
+       {QLCNIC_READ_MUX2, qlcnic_read_mux2},
+       {QLCNIC_READ_POLLRDMWR, qlcnic_read_pollrdmwr},
+       {QLCNIC_DUMP_READ_ROM, qlcnic_83xx_dump_rom},
+       {QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
+       {QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
+       {QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
+       {QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
+};
+
+static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
+{
+       uint64_t sum = 0;
+       int count = temp_size / sizeof(uint32_t);
+       while (count-- > 0)
+               sum += *temp_buffer++;
+       while (sum >> 32)
+               sum = (sum & 0xFFFFFFFF) + (sum >> 32);
+       return ~sum;
+}
+
+static int qlcnic_fw_flash_get_minidump_temp(struct qlcnic_adapter *adapter,
+                                            u8 *buffer, u32 size)
+{
+       int ret = 0;
+
+       if (qlcnic_82xx_check(adapter))
+               return -EIO;
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       ret = qlcnic_83xx_lockless_flash_read32(adapter,
+                                               QLC_83XX_MINIDUMP_FLASH,
+                                               buffer, size / sizeof(u32));
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return ret;
+}
+
+static int
+qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+                                      struct qlcnic_cmd_args *cmd)
+{
+       struct qlcnic_dump_template_hdr tmp_hdr;
+       u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+       int ret = 0;
+
+       if (qlcnic_82xx_check(adapter))
+               return -EIO;
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       ret = qlcnic_83xx_lockless_flash_read32(adapter,
+                                               QLC_83XX_MINIDUMP_FLASH,
+                                               (u8 *)&tmp_hdr, size);
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       cmd->rsp.arg[2] = tmp_hdr.size;
+       cmd->rsp.arg[3] = tmp_hdr.version;
+
+       return ret;
+}
+
+static int qlcnic_fw_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+                                           u32 *version, u32 *temp_size,
+                                           u8 *use_flash_temp)
+{
+       int err = 0;
+       struct qlcnic_cmd_args cmd;
+
+       if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TEMP_SIZE))
+               return -ENOMEM;
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               if (qlcnic_fw_flash_get_minidump_temp_size(adapter, &cmd)) {
+                       qlcnic_free_mbx_args(&cmd);
+                       return -EIO;
+               }
+               *use_flash_temp = 1;
+       }
+
+       *temp_size = cmd.rsp.arg[2];
+       *version = cmd.rsp.arg[3];
+       qlcnic_free_mbx_args(&cmd);
+
+       if (!(*temp_size))
+               return -EIO;
+
+       return 0;
+}
+
+static int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
+                                            u32 *buffer, u32 temp_size)
+{
+       int err = 0, i;
+       void *tmp_addr;
+       __le32 *tmp_buf;
+       struct qlcnic_cmd_args cmd;
+       dma_addr_t tmp_addr_t = 0;
+
+       tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
+                                     &tmp_addr_t, GFP_KERNEL);
+       if (!tmp_addr) {
+               dev_err(&adapter->pdev->dev,
+                       "Can't get memory for FW dump template\n");
+               return -ENOMEM;
+       }
+
+       if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
+               err = -ENOMEM;
+               goto free_mem;
+       }
+
+       cmd.req.arg[1] = LSD(tmp_addr_t);
+       cmd.req.arg[2] = MSD(tmp_addr_t);
+       cmd.req.arg[3] = temp_size;
+       err = qlcnic_issue_cmd(adapter, &cmd);
+
+       tmp_buf = tmp_addr;
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               for (i = 0; i < temp_size / sizeof(u32); i++)
+                       *buffer++ = __le32_to_cpu(*tmp_buf++);
+       }
+
+       qlcnic_free_mbx_args(&cmd);
+
+free_mem:
+       dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
+
+       return err;
+}
+
+int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+{
+       int err;
+       u32 temp_size = 0;
+       u32 version, csum, *tmp_buf;
+       struct qlcnic_hardware_context *ahw;
+       struct qlcnic_dump_template_hdr *tmpl_hdr;
+       u8 use_flash_temp = 0;
+
+       ahw = adapter->ahw;
+
+       err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
+                                              &use_flash_temp);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Can't get template size %d\n", err);
+               return -EIO;
+       }
+
+       ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
+       if (!ahw->fw_dump.tmpl_hdr)
+               return -ENOMEM;
+
+       tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+       if (use_flash_temp)
+               goto flash_temp;
+
+       err = __qlcnic_fw_cmd_get_minidump_temp(adapter, tmp_buf, temp_size);
+
+       if (err) {
+flash_temp:
+               err = qlcnic_fw_flash_get_minidump_temp(adapter, (u8 *)tmp_buf,
+                                                       temp_size);
+
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "Failed to get minidump template header %d\n",
+                               err);
+                       vfree(ahw->fw_dump.tmpl_hdr);
+                       ahw->fw_dump.tmpl_hdr = NULL;
+                       return -EIO;
+               }
+       }
+
+       csum = qlcnic_temp_checksum((uint32_t *)tmp_buf, temp_size);
+
+       if (csum) {
+               dev_err(&adapter->pdev->dev,
+                       "Template header checksum validation failed\n");
+               vfree(ahw->fw_dump.tmpl_hdr);
+               ahw->fw_dump.tmpl_hdr = NULL;
+               return -EIO;
+       }
+
+       tmpl_hdr = ahw->fw_dump.tmpl_hdr;
+       tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+       ahw->fw_dump.enable = 1;
+
+       return 0;
+}
+
 int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 {
        __le32 *buffer;
+       u32 ocm_window;
        char mesg[64];
        char *msg[] = {mesg, NULL};
        int i, k, ops_cnt, ops_index, dump_size = 0;
@@ -550,12 +906,23 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
        struct qlcnic_dump_entry *entry;
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
        struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
+       static const struct qlcnic_dump_operations *fw_dump_ops;
+       struct qlcnic_hardware_context *ahw;
+
+       ahw = adapter->ahw;
+
+       if (!fw_dump->enable) {
+               dev_info(&adapter->pdev->dev, "Dump not enabled\n");
+               return -EIO;
+       }
 
        if (fw_dump->clr) {
                dev_info(&adapter->pdev->dev,
                         "Previous dump not cleared, not capturing dump\n");
                return -EIO;
        }
+
+       netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
        /* Calculate the size for dump data area only */
        for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
                if (i & tmpl_hdr->drv_cap_mask)
@@ -573,11 +940,21 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
        buffer = fw_dump->data;
        fw_dump->size = dump_size;
        no_entries = tmpl_hdr->num_entries;
-       ops_cnt = ARRAY_SIZE(fw_dump_ops);
        entry_offset = tmpl_hdr->offset;
        tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
        tmpl_hdr->sys_info[1] = adapter->fw_version;
 
+       if (qlcnic_82xx_check(adapter)) {
+               ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
+               fw_dump_ops = qlcnic_fw_dump_ops;
+       } else {
+               ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
+               fw_dump_ops = qlcnic_83xx_fw_dump_ops;
+               ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
+               tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
+               tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
+       }
+
        for (i = 0; i < no_entries; i++) {
                entry = (void *)tmpl_hdr + entry_offset;
                if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
@@ -585,6 +962,7 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
                        entry_offset += entry->hdr.offset;
                        continue;
                }
+
                /* Find the handler for this entry */
                ops_index = 0;
                while (ops_index < ops_cnt) {
@@ -592,16 +970,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
                                break;
                        ops_index++;
                }
+
                if (ops_index == ops_cnt) {
                        dev_info(&adapter->pdev->dev,
                                 "Invalid entry type %d, exiting dump\n",
                                 entry->hdr.type);
                        goto error;
                }
+
                /* Collect dump for this entry */
                dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
-               if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry,
-                                                    dump))
+               if (!qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, dump))
                        entry->hdr.flags |= QLCNIC_DUMP_SKIP;
                buf_offset += entry->hdr.cap_size;
                entry_offset += entry->hdr.offset;
@@ -616,8 +995,8 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
                fw_dump->clr = 1;
                snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
                         adapter->netdev->name);
-               dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
-                        fw_dump->size);
+               dev_info(&adapter->pdev->dev, "%s: Dump data, %d bytes captured\n",
+                        adapter->netdev->name, fw_dump->size);
                /* Send a udev event to notify availability of FW dump */
                kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
                return 0;
@@ -626,3 +1005,21 @@ error:
        vfree(fw_dump->data);
        return -EINVAL;
 }
+
+void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
+{
+       u32 prev_version, current_version;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
+       struct pci_dev *pdev = adapter->pdev;
+
+       prev_version = adapter->fw_version;
+       current_version = qlcnic_83xx_get_fw_version(adapter);
+
+       if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
+               if (fw_dump->tmpl_hdr)
+                       vfree(fw_dump->tmpl_hdr);
+               if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+                       dev_info(&pdev->dev, "Supports FW dump capability\n");
+       }
+}
index 341d37c867ff17a4eed819ba3c6e5bdc794d3892..504506349ac1cd1af3b8e5d4d6b5e7b8ac6fdb9a 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/interrupt.h>
 
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
 
 #include <linux/swab.h>
 #include <linux/dma-mapping.h>
 #include <linux/aer.h>
 #include <linux/log2.h>
 
+#include <linux/sysfs.h>
+
+#define QLC_STATUS_UNSUPPORTED_CMD     -2
+
 int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
 {
        return -EOPNOTSUPP;
@@ -40,7 +45,7 @@ static ssize_t qlcnic_store_bridged_mode(struct device *dev,
        if (strict_strtoul(buf, 2, &new))
                goto err_out;
 
-       if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
+       if (!qlcnic_config_bridged_mode(adapter, !!new))
                ret = len;
 
 err_out:
@@ -80,9 +85,7 @@ static ssize_t qlcnic_show_diag_mode(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%d\n",
-                      !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+       return sprintf(buf, "%d\n", !!(adapter->flags & QLCNIC_DIAG_ENABLED));
 }
 
 static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon,
@@ -111,10 +114,11 @@ static ssize_t qlcnic_store_beacon(struct device *dev,
                                   const char *buf, size_t len)
 {
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       int max_sds_rings = adapter->max_sds_rings;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int err, max_sds_rings = adapter->max_sds_rings;
        u16 beacon;
        u8 b_state, b_rate;
-       int err;
+       unsigned long h_beacon;
 
        if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
                dev_warn(dev,
@@ -122,6 +126,41 @@ static ssize_t qlcnic_store_beacon(struct device *dev,
                return -EOPNOTSUPP;
        }
 
+       if (qlcnic_83xx_check(adapter) &&
+           !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+               if (kstrtoul(buf, 2, &h_beacon))
+                       return -EINVAL;
+
+               if (ahw->beacon_state == h_beacon)
+                       return len;
+
+               rtnl_lock();
+               if (!ahw->beacon_state) {
+                       if (test_and_set_bit(__QLCNIC_LED_ENABLE,
+                                            &adapter->state)) {
+                               rtnl_unlock();
+                               return -EBUSY;
+                       }
+               }
+               if (h_beacon) {
+                       err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
+                       if (err)
+                               goto beacon_err;
+               } else {
+                       err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
+                       if (err)
+                               goto beacon_err;
+               }
+               /* set the current beacon state */
+               ahw->beacon_state = h_beacon;
+beacon_err:
+               if (!ahw->beacon_state)
+                       clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+               rtnl_unlock();
+               return len;
+       }
+
        if (len != sizeof(u16))
                return QL_STATUS_INVALID_PARAM;
 
@@ -154,11 +193,10 @@ static ssize_t qlcnic_store_beacon(struct device *dev,
        }
 
        err = qlcnic_config_led(adapter, b_state, b_rate);
-
-       if (!err) {
+       if (!err)
                err = len;
-               adapter->ahw->beacon_state = b_state;
-       }
+       else
+               ahw->beacon_state = b_state;
 
        if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
                qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
@@ -207,21 +245,13 @@ static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 data;
-       u64 qmdata;
        int ret;
 
        ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
+       qlcnic_read_crb(adapter, buf, offset, size);
 
-       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
-               qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
-               memcpy(buf, &qmdata, size);
-       } else {
-               data = QLCRD32(adapter, offset);
-               memcpy(buf, &data, size);
-       }
        return size;
 }
 
@@ -231,21 +261,13 @@ static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 data;
-       u64 qmdata;
        int ret;
 
        ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
-               memcpy(&qmdata, buf, size);
-               qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
-       } else {
-               memcpy(&data, buf, size);
-               QLCWR32(adapter, offset, data);
-       }
+       qlcnic_write_crb(adapter, buf, offset, size);
        return size;
 }
 
@@ -303,33 +325,44 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
        return size;
 }
 
+static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
+{
+       int i;
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+               if (adapter->npars[i].pci_func == pci_func)
+                       return i;
+       }
+
+       return -1;
+}
+
 static int validate_pm_config(struct qlcnic_adapter *adapter,
                              struct qlcnic_pm_func_cfg *pm_cfg, int count)
 {
-       u8 src_pci_func, s_esw_id, d_esw_id, dest_pci_func;
-       int i;
+       u8 src_pci_func, s_esw_id, d_esw_id;
+       u8 dest_pci_func;
+       int i, src_index, dest_index;
 
        for (i = 0; i < count; i++) {
                src_pci_func = pm_cfg[i].pci_func;
                dest_pci_func = pm_cfg[i].dest_npar;
-               if (src_pci_func >= QLCNIC_MAX_PCI_FUNC ||
-                   dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
-                       return QL_STATUS_INVALID_PARAM;
+               src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func);
 
-               if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+               if (src_index < 0)
                        return QL_STATUS_INVALID_PARAM;
 
-               if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
+               dest_index = qlcnic_is_valid_nic_func(adapter, dest_pci_func);
+               if (dest_index < 0)
                        return QL_STATUS_INVALID_PARAM;
 
-               s_esw_id = adapter->npars[src_pci_func].phy_port;
-               d_esw_id = adapter->npars[dest_pci_func].phy_port;
+               s_esw_id = adapter->npars[src_index].phy_port;
+               d_esw_id = adapter->npars[dest_index].phy_port;
 
                if (s_esw_id != d_esw_id)
                        return QL_STATUS_INVALID_PARAM;
        }
-       return 0;
 
+       return 0;
 }
 
 static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
@@ -342,7 +375,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        struct qlcnic_pm_func_cfg *pm_cfg;
        u32 id, action, pci_func;
-       int count, rem, i, ret;
+       int count, rem, i, ret, index;
 
        count   = size / sizeof(struct qlcnic_pm_func_cfg);
        rem     = size % sizeof(struct qlcnic_pm_func_cfg);
@@ -350,26 +383,32 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
                return QL_STATUS_INVALID_PARAM;
 
        pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
-
        ret = validate_pm_config(adapter, pm_cfg, count);
+
        if (ret)
                return ret;
        for (i = 0; i < count; i++) {
                pci_func = pm_cfg[i].pci_func;
                action = !!pm_cfg[i].action;
-               id = adapter->npars[pci_func].phy_port;
-               ret = qlcnic_config_port_mirroring(adapter, id, action,
-                                                  pci_func);
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               if (index < 0)
+                       return QL_STATUS_INVALID_PARAM;
+
+               id = adapter->npars[index].phy_port;
+               ret = qlcnic_config_port_mirroring(adapter, id,
+                                                  action, pci_func);
                if (ret)
                        return ret;
        }
 
        for (i = 0; i < count; i++) {
                pci_func = pm_cfg[i].pci_func;
-               id = adapter->npars[pci_func].phy_port;
-               adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
-               adapter->npars[pci_func].dest_npar = id;
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               id = adapter->npars[index].phy_port;
+               adapter->npars[index].enable_pm = !!pm_cfg[i].action;
+               adapter->npars[index].dest_npar = id;
        }
+
        return size;
 }
 
@@ -383,16 +422,19 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
        int i;
+       u8 pci_func;
 
        if (size != sizeof(pm_cfg))
                return QL_STATUS_INVALID_PARAM;
 
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-                       continue;
-               pm_cfg[i].action = adapter->npars[i].enable_pm;
-               pm_cfg[i].dest_npar = 0;
-               pm_cfg[i].pci_func = i;
+       memset(&pm_cfg, 0,
+              sizeof(struct qlcnic_pm_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+               pci_func = adapter->npars[i].pci_func;
+               pm_cfg[pci_func].action = adapter->npars[i].enable_pm;
+               pm_cfg[pci_func].dest_npar = 0;
+               pm_cfg[pci_func].pci_func = i;
        }
        memcpy(buf, &pm_cfg, size);
 
@@ -404,24 +446,33 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
 {
        u32 op_mode;
        u8 pci_func;
-       int i;
+       int i, ret;
 
-       op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+       if (qlcnic_82xx_check(adapter))
+               op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+       else
+               op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
 
        for (i = 0; i < count; i++) {
                pci_func = esw_cfg[i].pci_func;
                if (pci_func >= QLCNIC_MAX_PCI_FUNC)
                        return QL_STATUS_INVALID_PARAM;
 
-               if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
-                       if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+               if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+                       if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
                                return QL_STATUS_INVALID_PARAM;
-               }
 
                switch (esw_cfg[i].op_mode) {
                case QLCNIC_PORT_DEFAULTS:
-                       if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
-                                           QLCNIC_NON_PRIV_FUNC) {
+                       if (qlcnic_82xx_check(adapter)) {
+                               ret = QLC_DEV_GET_DRV(op_mode, pci_func);
+                       } else {
+                               ret = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+                                                                 pci_func);
+                               esw_cfg[i].offload_flags = 0;
+                       }
+
+                       if (ret != QLCNIC_NON_PRIV_FUNC) {
                                if (esw_cfg[i].mac_anti_spoof != 0)
                                        return QL_STATUS_INVALID_PARAM;
                                if (esw_cfg[i].mac_override != 1)
@@ -444,6 +495,7 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
                        return QL_STATUS_INVALID_PARAM;
                }
        }
+
        return 0;
 }
 
@@ -458,7 +510,8 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
        struct qlcnic_esw_func_cfg *esw_cfg;
        struct qlcnic_npar_info *npar;
        int count, rem, i, ret;
-       u8 pci_func, op_mode = 0;
+       int index;
+       u8 op_mode = 0, pci_func;
 
        count   = size / sizeof(struct qlcnic_esw_func_cfg);
        rem     = size % sizeof(struct qlcnic_esw_func_cfg);
@@ -471,10 +524,9 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
                return ret;
 
        for (i = 0; i < count; i++) {
-               if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
+               if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
                        if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
                                return QL_STATUS_INVALID_PARAM;
-               }
 
                if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
                        continue;
@@ -503,7 +555,8 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
 
        for (i = 0; i < count; i++) {
                pci_func = esw_cfg[i].pci_func;
-               npar = &adapter->npars[pci_func];
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               npar = &adapter->npars[index];
                switch (esw_cfg[i].op_mode) {
                case QLCNIC_PORT_DEFAULTS:
                        npar->promisc_mode = esw_cfg[i].promisc_mode;
@@ -533,18 +586,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
-       u8 i;
+       u8 i, pci_func;
 
        if (size != sizeof(esw_cfg))
                return QL_STATUS_INVALID_PARAM;
 
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-                       continue;
-               esw_cfg[i].pci_func = i;
-               if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
+       memset(&esw_cfg, 0,
+              sizeof(struct qlcnic_esw_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+               pci_func = adapter->npars[i].pci_func;
+               esw_cfg[pci_func].pci_func = pci_func;
+               if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
                        return QL_STATUS_INVALID_PARAM;
        }
+
        memcpy(buf, &esw_cfg, size);
 
        return size;
@@ -558,10 +614,7 @@ static int validate_npar_config(struct qlcnic_adapter *adapter,
 
        for (i = 0; i < count; i++) {
                pci_func = np_cfg[i].pci_func;
-               if (pci_func >= QLCNIC_MAX_PCI_FUNC)
-                       return QL_STATUS_INVALID_PARAM;
-
-               if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+               if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
                        return QL_STATUS_INVALID_PARAM;
 
                if (!IS_VALID_BW(np_cfg[i].min_bw) ||
@@ -581,7 +634,7 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        struct qlcnic_info nic_info;
        struct qlcnic_npar_func_cfg *np_cfg;
-       int i, count, rem, ret;
+       int i, count, rem, ret, index;
        u8 pci_func;
 
        count   = size / sizeof(struct qlcnic_npar_func_cfg);
@@ -594,8 +647,10 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
        if (ret)
                return ret;
 
-       for (i = 0; i < count ; i++) {
+       for (i = 0; i < count; i++) {
                pci_func = np_cfg[i].pci_func;
+
+               memset(&nic_info, 0, sizeof(struct qlcnic_info));
                ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
                if (ret)
                        return ret;
@@ -605,12 +660,12 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
                ret = qlcnic_set_nic_info(adapter, &nic_info);
                if (ret)
                        return ret;
-               adapter->npars[i].min_bw = nic_info.min_tx_bw;
-               adapter->npars[i].max_bw = nic_info.max_tx_bw;
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               adapter->npars[index].min_bw = nic_info.min_tx_bw;
+               adapter->npars[index].max_bw = nic_info.max_tx_bw;
        }
 
        return size;
-
 }
 
 static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
@@ -628,8 +683,12 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
        if (size != sizeof(np_cfg))
                return QL_STATUS_INVALID_PARAM;
 
+       memset(&nic_info, 0, sizeof(struct qlcnic_info));
+       memset(&np_cfg, 0,
+              sizeof(struct qlcnic_npar_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
        for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+               if (qlcnic_is_valid_nic_func(adapter, i) < 0)
                        continue;
                ret = qlcnic_get_nic_info(adapter, &nic_info, i);
                if (ret)
@@ -644,6 +703,7 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
                np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
                np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
        }
+
        memcpy(buf, &np_cfg, size);
        return size;
 }
@@ -659,6 +719,9 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
        struct qlcnic_esw_statistics port_stats;
        int ret;
 
+       if (qlcnic_83xx_check(adapter))
+               return QLC_STATUS_UNSUPPORTED_CMD;
+
        if (size != sizeof(struct qlcnic_esw_statistics))
                return QL_STATUS_INVALID_PARAM;
 
@@ -691,6 +754,9 @@ static ssize_t qlcnic_sysfs_get_esw_stats(struct file *file,
        struct qlcnic_esw_statistics esw_stats;
        int ret;
 
+       if (qlcnic_83xx_check(adapter))
+               return QLC_STATUS_UNSUPPORTED_CMD;
+
        if (size != sizeof(struct qlcnic_esw_statistics))
                return QL_STATUS_INVALID_PARAM;
 
@@ -722,6 +788,9 @@ static ssize_t qlcnic_sysfs_clear_esw_stats(struct file *file,
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        int ret;
 
+       if (qlcnic_83xx_check(adapter))
+               return QLC_STATUS_UNSUPPORTED_CMD;
+
        if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
                return QL_STATUS_INVALID_PARAM;
 
@@ -744,10 +813,14 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
                                             char *buf, loff_t offset,
                                             size_t size)
 {
+
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        int ret;
 
+       if (qlcnic_83xx_check(adapter))
+               return QLC_STATUS_UNSUPPORTED_CMD;
+
        if (offset >= QLCNIC_MAX_PCI_FUNC)
                return QL_STATUS_INVALID_PARAM;
 
@@ -789,7 +862,10 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
                return ret;
        }
 
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+       memset(&pci_cfg, 0,
+              sizeof(struct qlcnic_pci_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
                pci_cfg[i].pci_func = pci_info[i].id;
                pci_cfg[i].func_type = pci_info[i].type;
                pci_cfg[i].port_num = pci_info[i].default_port;
@@ -797,6 +873,7 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
                pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
                memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
        }
+
        memcpy(buf, &pci_cfg, size);
        kfree(pci_info);
        return size;
@@ -897,7 +974,6 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
 void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
-       u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
        if (device_create_bin_file(dev, &bin_attr_port_stats))
                dev_info(dev, "failed to create port stats sysfs entry");
@@ -911,9 +987,6 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
        if (device_create_bin_file(dev, &bin_attr_mem))
                dev_info(dev, "failed to create mem sysfs entry\n");
 
-       if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-               return;
-
        if (device_create_bin_file(dev, &bin_attr_pci_config))
                dev_info(dev, "failed to create pci config sysfs entry");
        if (device_create_file(dev, &dev_attr_beacon))
@@ -936,7 +1009,6 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
-       u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
        device_remove_bin_file(dev, &bin_attr_port_stats);
 
@@ -945,8 +1017,6 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
        device_remove_file(dev, &dev_attr_diag_mode);
        device_remove_bin_file(dev, &bin_attr_crb);
        device_remove_bin_file(dev, &bin_attr_mem);
-       if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-               return;
        device_remove_bin_file(dev, &bin_attr_pci_config);
        device_remove_file(dev, &dev_attr_beacon);
        if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
@@ -958,3 +1028,23 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
        device_remove_bin_file(dev, &bin_attr_pm_config);
        device_remove_bin_file(dev, &bin_attr_esw_stats);
 }
+
+void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter)
+{
+       qlcnic_create_diag_entries(adapter);
+}
+
+void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+       qlcnic_remove_diag_entries(adapter);
+}
+
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter)
+{
+       qlcnic_create_diag_entries(adapter);
+}
+
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+       qlcnic_remove_diag_entries(adapter);
+}
index 3e73742024b0cb5af229df1336a9a3aeab653b1f..e9381584e4b3ae390010696cf2118bb0263a307b 100644 (file)
@@ -4586,7 +4586,6 @@ static int ql_init_device(struct pci_dev *pdev, struct net_device *ndev,
                goto err_out2;
        }
 
-       memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
        /* Keep local copy of current mac address. */
        memcpy(qdev->current_mac_addr, ndev->dev_addr, ndev->addr_len);
 
diff --git a/drivers/net/ethernet/racal/Kconfig b/drivers/net/ethernet/racal/Kconfig
deleted file mode 100644 (file)
index 01969e0..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Racal-Interlan device configuration
-#
-
-config NET_VENDOR_RACAL
-       bool "Racal-Interlan (Micom) NI devices"
-       default y
-       depends on ISA
-       ---help---
-         If you have a network (Ethernet) card belonging to this class, such
-         as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
-         available from <http://www.tldp.org/docs.html#howto>.
-
-         Note that the answer to this question doesn't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about NI cards. If you say Y, you will be asked for
-         your specific card in the following questions.
-
-if NET_VENDOR_RACAL
-
-config NI5010
-       tristate "NI5010 support (EXPERIMENTAL)"
-       depends on ISA && EXPERIMENTAL && BROKEN_ON_SMP
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y and read
-         the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>. Note that this is still
-         experimental code.
-
-         To compile this driver as a module, choose M here. The module
-         will be called ni5010.
-
-endif # NET_VENDOR_RACAL
diff --git a/drivers/net/ethernet/racal/Makefile b/drivers/net/ethernet/racal/Makefile
deleted file mode 100644 (file)
index 1e210ca..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Racal-Interlan network device drivers.
-#
-
-obj-$(CONFIG_NI5010) += ni5010.o
diff --git a/drivers/net/ethernet/racal/ni5010.c b/drivers/net/ethernet/racal/ni5010.c
deleted file mode 100644 (file)
index 8079822..0000000
+++ /dev/null
@@ -1,771 +0,0 @@
-/*     ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
- *
- *     Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
- *
- *     This software may be used and distributed according to the terms
- *     of the GNU General Public License, incorporated herein by reference.
- *
- *     The authors may be reached as:
- *             janpascal@vanbest.org           andi@lisas.de
- *
- *     Sources:
- *             Donald Becker's "skeleton.c"
- *             Crynwr ni5010 packet driver
- *
- *     Changes:
- *             v0.0: First test version
- *             v0.1: First working version
- *             v0.2:
- *             v0.3->v0.90: Now demand setting io and irq when loading as module
- *     970430  v0.91: modified for Linux 2.1.14
- *             v0.92: Implemented Andreas' (better) NI5010 probe
- *     970503  v0.93: Fixed auto-irq failure on warm reboot (JB)
- *     970623  v1.00: First kernel version (AM)
- *     970814  v1.01: Added detection of onboard receive buffer size (AM)
- *     060611  v1.02: slight cleanup: email addresses, driver modernization.
- *     Bugs:
- *             - not SMP-safe (no locking of I/O accesses)
- *             - Note that you have to patch ifconfig for the new /proc/net/dev
- *             format. It gives incorrect stats otherwise.
- *
- *     To do:
- *             Fix all bugs :-)
- *             Move some stuff to chipset_init()
- *             Handle xmt errors other than collisions
- *             Complete merge with Andreas' driver
- *             Implement ring buffers (Is this useful? You can't squeeze
- *                     too many packet in a 2k buffer!)
- *             Implement DMA (Again, is this useful? Some docs say DMA is
- *                     slower than programmed I/O)
- *
- *     Compile with:
- *             gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \
- *                     -DMODULE -c ni5010.c
- *
- *     Insert with e.g.:
- *             insmod ni5010.ko io=0x300 irq=5
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni5010.h"
-
-static const char boardname[] = "NI5010";
-static char version[] __initdata =
-       "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
-
-/* bufsize_rcv == 0 means autoprobing */
-static unsigned int bufsize_rcv;
-
-#define JUMPERED_INTERRUPTS    /* IRQ line jumpered on board */
-#undef JUMPERED_DMA            /* No DMA used */
-#undef FULL_IODETECT           /* Only detect in portlist */
-
-#ifndef FULL_IODETECT
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int ports[] __initdata =
-       { 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 };
-#endif
-
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef NI5010_DEBUG
-#define NI5010_DEBUG 0
-#endif
-
-/* Information that needs to be kept for each board. */
-struct ni5010_local {
-       int o_pkt_size;
-       spinlock_t lock;
-};
-
-/* Index to functions, as function prototypes. */
-
-static int     ni5010_probe1(struct net_device *dev, int ioaddr);
-static int     ni5010_open(struct net_device *dev);
-static int     ni5010_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id);
-static void    ni5010_rx(struct net_device *dev);
-static void    ni5010_timeout(struct net_device *dev);
-static int     ni5010_close(struct net_device *dev);
-static void    ni5010_set_multicast_list(struct net_device *dev);
-static void    reset_receiver(struct net_device *dev);
-
-static int     process_xmt_interrupt(struct net_device *dev);
-#define tx_done(dev) 1
-static void    hardware_send_packet(struct net_device *dev, char *buf, int length, int pad);
-static void    chipset_init(struct net_device *dev, int startp);
-static void    dump_packet(void *buf, int len);
-static void    ni5010_show_registers(struct net_device *dev);
-
-static int io;
-static int irq;
-
-struct net_device * __init ni5010_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local));
-       int *port;
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-       }
-
-       PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name));
-
-       if (io > 0x1ff) {       /* Check a single specified location. */
-               err = ni5010_probe1(dev, io);
-       } else if (io != 0) {   /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-#ifdef FULL_IODETECT
-               for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20)
-                       ;
-               if (io == 0x400)
-                       err = -ENODEV;
-
-#else
-               for (port = ports; *port && ni5010_probe1(dev, *port); port++)
-                       ;
-               if (!*port)
-                       err = -ENODEV;
-#endif /* FULL_IODETECT */
-       }
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       release_region(dev->base_addr, NI5010_IO_EXTENT);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static inline int rd_port(int ioaddr)
-{
-       inb(IE_RBUF);
-       return inb(IE_SAPROM);
-}
-
-static void __init trigger_irq(int ioaddr)
-{
-               outb(0x00, EDLC_RESET); /* Clear EDLC hold RESET state */
-               outb(0x00, IE_RESET);   /* Board reset */
-               outb(0x00, EDLC_XMASK); /* Disable all Xmt interrupts */
-               outb(0x00, EDLC_RMASK); /* Disable all Rcv interrupt */
-               outb(0xff, EDLC_XCLR);  /* Clear all pending Xmt interrupts */
-               outb(0xff, EDLC_RCLR);  /* Clear all pending Rcv interrupts */
-               /*
-                * Transmit packet mode: Ignore parity, Power xcvr,
-                *      Enable loopback
-                */
-               outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
-               outb(RMD_BROADCAST, EDLC_RMODE); /* Receive normal&broadcast */
-               outb(XM_ALL, EDLC_XMASK);       /* Enable all Xmt interrupts */
-               udelay(50);                     /* FIXME: Necessary? */
-               outb(MM_EN_XMT|MM_MUX, IE_MMODE); /* Start transmission */
-}
-
-static const struct net_device_ops ni5010_netdev_ops = {
-       .ndo_open               = ni5010_open,
-       .ndo_stop               = ni5010_close,
-       .ndo_start_xmit         = ni5010_send_packet,
-       .ndo_set_rx_mode        = ni5010_set_multicast_list,
-       .ndo_tx_timeout         = ni5010_timeout,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-};
-
-/*
- *      This is the real probe routine.  Linux has a history of friendly device
- *      probes on the ISA bus.  A good device probes avoids doing writes, and
- *      verifies that the correct device exists and functions.
- */
-
-static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
-{
-       static unsigned version_printed;
-       struct ni5010_local *lp;
-       int i;
-       unsigned int data = 0;
-       int boguscount = 40;
-       int err = -ENODEV;
-
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-
-       if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname))
-               return -EBUSY;
-
-       /*
-        * This is no "official" probe method, I've rather tested which
-        * probe works best with my seven NI5010 cards
-        * (they have very different serial numbers)
-        * Suggestions or failure reports are very, very welcome !
-        * But I think it is a relatively good probe method
-        * since it doesn't use any "outb"
-        * It should be nearly 100% reliable !
-        * well-known WARNING: this probe method (like many others)
-        * will hang the system if a NE2000 card region is probed !
-        *
-        *   - Andreas
-        */
-
-       PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
-               dev->name, ioaddr));
-
-       if (inb(ioaddr+0) == 0xff)
-               goto out;
-
-       while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) &
-                rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff)
-       {
-               if (boguscount-- == 0)
-                       goto out;
-       }
-
-       PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name));
-
-       for (i=0; i<32; i++)
-               if ( (data = rd_port(ioaddr)) != 0xff) break;
-       if (data==0xff)
-               goto out;
-
-       PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name));
-
-       if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) ||
-           (rd_port(ioaddr) != SA_ADDR2))
-               goto out;
-
-       for (i=0; i<4; i++)
-               rd_port(ioaddr);
-
-       if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) ||
-            (rd_port(ioaddr) != NI5010_MAGICVAL2) )
-               goto out;
-
-       PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name));
-
-       if (NI5010_DEBUG && version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
-
-       printk("NI5010 ethercard probe at 0x%x: ", ioaddr);
-
-       dev->base_addr = ioaddr;
-
-       for (i=0; i<6; i++) {
-               outw(i, IE_GP);
-               dev->dev_addr[i] = inb(IE_SAPROM);
-       }
-       printk("%pM ", dev->dev_addr);
-
-       PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
-
-#ifdef JUMPERED_INTERRUPTS
-       if (dev->irq == 0xff)
-               ;
-       else if (dev->irq < 2) {
-               unsigned long irq_mask;
-
-               PRINTK2((KERN_DEBUG "%s: I/O #5 passed!\n", dev->name));
-
-               irq_mask = probe_irq_on();
-               trigger_irq(ioaddr);
-               mdelay(20);
-               dev->irq = probe_irq_off(irq_mask);
-
-               PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name));
-
-               if (dev->irq == 0) {
-                       err = -EAGAIN;
-                       printk(KERN_WARNING "%s: no IRQ found!\n", dev->name);
-                       goto out;
-               }
-               PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name));
-       } else if (dev->irq == 2) {
-               dev->irq = 9;
-       }
-#endif /* JUMPERED_INTERRUPTS */
-       PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
-
-       /* DMA is not supported (yet?), so no use detecting it */
-       lp = netdev_priv(dev);
-
-       spin_lock_init(&lp->lock);
-
-       PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name));
-
-/* get the size of the onboard receive buffer
- * higher addresses than bufsize are wrapped into real buffer
- * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer
- */
-       if (!bufsize_rcv) {
-               outb(1, IE_MMODE);      /* Put Rcv buffer on system bus */
-               outw(0, IE_GP);         /* Point GP at start of packet */
-               outb(0, IE_RBUF);       /* set buffer byte 0 to 0 */
-               for (i = 1; i < 0xff; i++) {
-                       outw(i << 8, IE_GP); /* Point GP at packet size to be tested */
-                       outb(i, IE_RBUF);
-                       outw(0x0, IE_GP); /* Point GP at start of packet */
-                       data = inb(IE_RBUF);
-                       if (data == i) break;
-               }
-               bufsize_rcv = i << 8;
-               outw(0, IE_GP);         /* Point GP at start of packet */
-               outb(0, IE_RBUF);       /* set buffer byte 0 to 0 again */
-       }
-        printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
-
-       dev->netdev_ops         = &ni5010_netdev_ops;
-       dev->watchdog_timeo     = HZ/20;
-
-       dev->flags &= ~IFF_MULTICAST;   /* Multicast doesn't work */
-
-       /* Shut up the ni5010 */
-       outb(0, EDLC_RMASK);    /* Mask all receive interrupts */
-       outb(0, EDLC_XMASK);    /* Mask all xmit interrupts */
-       outb(0xff, EDLC_RCLR);  /* Kill all pending rcv interrupts */
-       outb(0xff, EDLC_XCLR);  /* Kill all pending xmt interrupts */
-
-       printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
-       if (dev->dma)
-               printk(" & DMA %d", dev->dma);
-       printk(".\n");
-       return 0;
-out:
-       release_region(dev->base_addr, NI5010_IO_EXTENT);
-       return err;
-}
-
-/*
- * Open/initialize the board.  This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- */
-
-static int ni5010_open(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       int i;
-
-       PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
-
-       if (request_irq(dev->irq, ni5010_interrupt, 0, boardname, dev)) {
-               printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-       PRINTK3((KERN_DEBUG "%s: passed open() #1\n", dev->name));
-        /*
-         * Always allocate the DMA channel after the IRQ,
-         * and clean up on failure.
-         */
-#ifdef JUMPERED_DMA
-        if (request_dma(dev->dma, cardname)) {
-               printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
-                free_irq(dev->irq, NULL);
-                return -EAGAIN;
-        }
-#endif /* JUMPERED_DMA */
-
-       PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
-       /* Reset the hardware here.  Don't forget to set the station address. */
-
-       outb(RS_RESET, EDLC_RESET);     /* Hold up EDLC_RESET while configing board */
-       outb(0, IE_RESET);              /* Hardware reset of ni5010 board */
-       outb(XMD_LBC, EDLC_XMODE);      /* Only loopback xmits */
-
-       PRINTK3((KERN_DEBUG "%s: passed open() #3\n", dev->name));
-       /* Set the station address */
-       for(i = 0;i < 6; i++) {
-               outb(dev->dev_addr[i], EDLC_ADDR + i);
-       }
-
-       PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
-       outb(0, EDLC_XMASK);    /* No xmit interrupts for now */
-       outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
-                               /* Normal packet xmit mode */
-       outb(0xff, EDLC_XCLR);  /* Clear all pending xmit interrupts */
-       outb(RMD_BROADCAST, EDLC_RMODE);
-                               /* Receive broadcast and normal packets */
-       reset_receiver(dev);    /* Ready ni5010 for receiving packets */
-
-       outb(0, EDLC_RESET);    /* Un-reset the ni5010 */
-
-       netif_start_queue(dev);
-
-       if (NI5010_DEBUG) ni5010_show_registers(dev);
-
-       PRINTK((KERN_DEBUG "%s: open successful\n", dev->name));
-       return 0;
-}
-
-static void reset_receiver(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name));
-       outw(0, IE_GP);         /* Receive packet at start of buffer */
-       outb(0xff, EDLC_RCLR);  /* Clear all pending rcv interrupts */
-       outb(0, IE_MMODE);      /* Put EDLC to rcv buffer */
-       outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */
-       outb(0xff, EDLC_RMASK); /* Enable all rcv interrupts */
-}
-
-static void ni5010_timeout(struct net_device *dev)
-{
-       printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
-                  tx_done(dev) ? "IRQ conflict" : "network cable problem");
-       /* Try to restart the adaptor. */
-       /* FIXME: Give it a real kick here */
-       chipset_init(dev, 1);
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue(dev);
-}
-
-static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-       int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-
-       PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name));
-
-       /*
-         * Block sending
-        */
-
-       netif_stop_queue(dev);
-       hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
-       dev_kfree_skb (skb);
-       return NETDEV_TX_OK;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct ni5010_local *lp;
-       int ioaddr, status;
-       int xmit_was_error = 0;
-
-       PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name));
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-
-       spin_lock(&lp->lock);
-       status = inb(IE_ISTAT);
-       PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status));
-
-        if ((status & IS_R_INT) == 0) ni5010_rx(dev);
-
-        if ((status & IS_X_INT) == 0) {
-                xmit_was_error = process_xmt_interrupt(dev);
-        }
-
-        if ((status & IS_DMA_INT) == 0) {
-                PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name));
-                outb(0, IE_DMA_RST); /* Reset DMA int */
-        }
-
-       if (!xmit_was_error)
-               reset_receiver(dev);
-       spin_unlock(&lp->lock);
-       return IRQ_HANDLED;
-}
-
-
-static void dump_packet(void *buf, int len)
-{
-       int i;
-
-       printk(KERN_DEBUG "Packet length = %#4x\n", len);
-       for (i = 0; i < len; i++){
-               if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i);
-               if (i % 2 == 0) printk(" ");
-               printk("%2.2x", ((unsigned char *)buf)[i]);
-               if (i % 16 == 15) printk("\n");
-       }
-       printk("\n");
-}
-
-/* We have a good packet, get it out of the buffer. */
-static void ni5010_rx(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       unsigned char rcv_stat;
-       struct sk_buff *skb;
-       int i_pkt_size;
-
-       PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
-
-       rcv_stat = inb(EDLC_RSTAT);
-       PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
-
-       if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
-               PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
-               dev->stats.rx_errors++;
-               if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++;
-               if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++;
-               if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++;
-               if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++;
-               outb(0xff, EDLC_RCLR); /* Clear the interrupt */
-               return;
-       }
-
-        outb(0xff, EDLC_RCLR);  /* Clear the interrupt */
-
-       i_pkt_size = inw(IE_RCNT);
-       if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
-               PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
-                       dev->name, i_pkt_size));
-               dev->stats.rx_errors++;
-               dev->stats.rx_length_errors++;
-               return;
-       }
-
-       /* Malloc up new buffer. */
-       skb = netdev_alloc_skb(dev, i_pkt_size + 3);
-       if (skb == NULL) {
-               printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-               dev->stats.rx_dropped++;
-               return;
-       }
-
-       skb_reserve(skb, 2);
-
-       /* Read packet into buffer */
-        outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */
-       outw(0, IE_GP); /* Seek to beginning of packet */
-       insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
-
-       if (NI5010_DEBUG >= 4)
-               dump_packet(skb->data, skb->len);
-
-       skb->protocol = eth_type_trans(skb,dev);
-       netif_rx(skb);
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += i_pkt_size;
-
-       PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
-               dev->name, i_pkt_size));
-}
-
-static int process_xmt_interrupt(struct net_device *dev)
-{
-       struct ni5010_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int xmit_stat;
-
-       PRINTK2((KERN_DEBUG "%s: entering process_xmt_interrupt\n", dev->name));
-
-       xmit_stat = inb(EDLC_XSTAT);
-       PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat));
-
-       outb(0, EDLC_XMASK);    /* Disable xmit IRQ's */
-       outb(0xff, EDLC_XCLR);  /* Clear all pending xmit IRQ's */
-
-       if (xmit_stat & XS_COLL){
-               PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
-                       dev->name));
-               outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP);
-               /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
-               outb(MM_EN_XMT | MM_MUX, IE_MMODE);
-               outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */
-               dev->stats.collisions++;
-               return 1;
-       }
-
-       /* FIXME: handle other xmt error conditions */
-
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += lp->o_pkt_size;
-       netif_wake_queue(dev);
-
-       PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
-               dev->name, lp->o_pkt_size));
-
-       return 0;
-}
-
-/* The inverse routine to ni5010_open(). */
-static int ni5010_close(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef JUMPERED_INTERRUPTS
-       free_irq(dev->irq, NULL);
-#endif
-       /* Put card in held-RESET state */
-       outb(0, IE_MMODE);
-       outb(RS_RESET, EDLC_RESET);
-
-       netif_stop_queue(dev);
-
-       PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname));
-       return 0;
-
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1      Promiscuous mode, receive all packets
-   num_addrs == 0       Normal mode, clear multicast list
-   num_addrs > 0        Multicast mode, receive normal and MC packets, and do
-                        best-effort filtering.
-*/
-static void ni5010_set_multicast_list(struct net_device *dev)
-{
-       short ioaddr = dev->base_addr;
-
-       PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
-
-       if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI ||
-           !netdev_mc_empty(dev)) {
-               outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
-               PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
-       } else {
-               PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
-               outb(RMD_BROADCAST, EDLC_RMODE);  /* Disable promiscuous mode, use normal mode */
-       }
-}
-
-static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad)
-{
-       struct ni5010_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned long flags;
-       unsigned int buf_offs;
-
-       PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name));
-
-        if (length > ETH_FRAME_LEN) {
-                PRINTK((KERN_WARNING "%s: packet too large, not possible\n",
-                        dev->name));
-                return;
-        }
-
-       if (NI5010_DEBUG) ni5010_show_registers(dev);
-
-       if (inb(IE_ISTAT) & IS_EN_XMT) {
-               PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
-                       dev->name));
-               return;
-       }
-
-       if (NI5010_DEBUG > 3) dump_packet(buf, length);
-
-       buf_offs = NI5010_BUFSIZE - length - pad;
-
-       spin_lock_irqsave(&lp->lock, flags);
-       lp->o_pkt_size = length + pad;
-
-       outb(0, EDLC_RMASK);    /* Mask all receive interrupts */
-       outb(0, IE_MMODE);      /* Put Xmit buffer on system bus */
-       outb(0xff, EDLC_RCLR);  /* Clear out pending rcv interrupts */
-
-       outw(buf_offs, IE_GP); /* Point GP at start of packet */
-       outsb(IE_XBUF, buf, length); /* Put data in buffer */
-       while(pad--)
-               outb(0, IE_XBUF);
-
-       outw(buf_offs, IE_GP); /* Rewrite where packet starts */
-
-       /* should work without that outb() (Crynwr used it) */
-       /*outb(MM_MUX, IE_MMODE);*/ /* Xmt buffer to EDLC bus */
-       outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */
-       outb(XM_ALL, EDLC_XMASK); /* Cause interrupt after completion or fail */
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       netif_wake_queue(dev);
-
-       if (NI5010_DEBUG) ni5010_show_registers(dev);
-}
-
-static void chipset_init(struct net_device *dev, int startp)
-{
-       /* FIXME: Move some stuff here */
-       PRINTK3((KERN_DEBUG "%s: doing NOTHING in chipset_init\n", dev->name));
-}
-
-static void ni5010_show_registers(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT)));
-       PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK)));
-       PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT)));
-       PRINTK3((KERN_DEBUG "%s: RMASK %#2.2x\n", dev->name, inb(EDLC_RMASK)));
-       PRINTK3((KERN_DEBUG "%s: RMODE %#2.2x\n", dev->name, inb(EDLC_RMODE)));
-       PRINTK3((KERN_DEBUG "%s: XMODE %#2.2x\n", dev->name, inb(EDLC_XMODE)));
-       PRINTK3((KERN_DEBUG "%s: ISTAT %#2.2x\n", dev->name, inb(IE_ISTAT)));
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni5010;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "ni5010 I/O base address");
-MODULE_PARM_DESC(irq, "ni5010 IRQ number");
-
-static int __init ni5010_init_module(void)
-{
-       PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
-       /*
-       if(io <= 0 || irq == 0){
-               printk(KERN_WARNING "%s: Autoprobing not allowed for modules.\n", boardname);
-               printk(KERN_WARNING "%s: Set symbols 'io' and 'irq'\n", boardname);
-               return -EINVAL;
-       }
-       */
-       if (io <= 0){
-               printk(KERN_WARNING "%s: Autoprobing for modules is hazardous, trying anyway..\n", boardname);
-       }
-
-       PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io));
-       dev_ni5010 = ni5010_probe(-1);
-       if (IS_ERR(dev_ni5010))
-               return PTR_ERR(dev_ni5010);
-        return 0;
-}
-
-static void __exit ni5010_cleanup_module(void)
-{
-       PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
-       unregister_netdev(dev_ni5010);
-       release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
-       free_netdev(dev_ni5010);
-}
-module_init(ni5010_init_module);
-module_exit(ni5010_cleanup_module);
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/racal/ni5010.h b/drivers/net/ethernet/racal/ni5010.h
deleted file mode 100644 (file)
index e10e717..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Racal-Interlan ni5010 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1996 by Jan-Pascal van Best (jvbest@wi.leidenuniv.nl)
- *
- * I have done a look in the following sources:
- *   crynwr-packet-driver by Russ Nelson
- */
-
-#define NI5010_BUFSIZE 2048    /* number of bytes in a buffer */
-
-#define NI5010_MAGICVAL0 0x00  /* magic-values for ni5010 card */
-#define NI5010_MAGICVAL1 0x55
-#define NI5010_MAGICVAL2 0xAA
-
-#define SA_ADDR0 0x02
-#define SA_ADDR1 0x07
-#define SA_ADDR2 0x01
-
-/* The number of low I/O ports used by the ni5010 ethercard. */
-#define NI5010_IO_EXTENT       32
-
-#define PRINTK(x) if (NI5010_DEBUG) printk x
-#define PRINTK2(x) if (NI5010_DEBUG>=2) printk x
-#define PRINTK3(x) if (NI5010_DEBUG>=3) printk x
-
-/* The various IE command registers */
-#define EDLC_XSTAT     (ioaddr + 0x00) /* EDLC transmit csr */
-#define EDLC_XCLR      (ioaddr + 0x00) /* EDLC transmit "Clear IRQ" */
-#define EDLC_XMASK     (ioaddr + 0x01) /* EDLC transmit "IRQ Masks" */
-#define EDLC_RSTAT     (ioaddr + 0x02) /* EDLC receive csr */
-#define EDLC_RCLR      (ioaddr + 0x02) /* EDLC receive "Clear IRQ" */
-#define EDLC_RMASK     (ioaddr + 0x03) /* EDLC receive "IRQ Masks" */
-#define EDLC_XMODE     (ioaddr + 0x04) /* EDLC transmit Mode */
-#define EDLC_RMODE     (ioaddr + 0x05) /* EDLC receive Mode */
-#define EDLC_RESET     (ioaddr + 0x06) /* EDLC RESET register */
-#define EDLC_TDR1      (ioaddr + 0x07) /* "Time Domain Reflectometry" reg1 */
-#define EDLC_ADDR      (ioaddr + 0x08) /* EDLC station address, 6 bytes */
-                               /* 0x0E doesn't exist for r/w */
-#define EDLC_TDR2      (ioaddr + 0x0f) /* "Time Domain Reflectometry" reg2 */
-#define IE_GP          (ioaddr + 0x10) /* GP pointer (word register) */
-                               /* 0x11 is 2nd byte of GP Pointer */
-#define IE_RCNT                (ioaddr + 0x10) /* Count of bytes in rcv'd packet */
-                               /* 0x11 is 2nd byte of "Byte Count" */
-#define IE_MMODE       (ioaddr + 0x12) /* Memory Mode register */
-#define IE_DMA_RST     (ioaddr + 0x13) /* IE DMA Reset.  write only */
-#define IE_ISTAT       (ioaddr + 0x13) /* IE Interrupt Status.  read only */
-#define IE_RBUF                (ioaddr + 0x14) /* IE Receive Buffer port */
-#define IE_XBUF                (ioaddr + 0x15) /* IE Transmit Buffer port */
-#define IE_SAPROM      (ioaddr + 0x16) /* window on station addr prom */
-#define IE_RESET       (ioaddr + 0x17) /* any write causes Board Reset */
-
-/* bits in EDLC_XSTAT, interrupt clear on write, status when read */
-#define XS_TPOK                0x80    /* transmit packet successful */
-#define XS_CS          0x40    /* carrier sense */
-#define XS_RCVD                0x20    /* transmitted packet received */
-#define XS_SHORT       0x10    /* transmission media is shorted */
-#define XS_UFLW                0x08    /* underflow.  iff failed board */
-#define XS_COLL                0x04    /* collision occurred */
-#define XS_16COLL      0x02    /* 16th collision occurred */
-#define XS_PERR                0x01    /* parity error */
-
-#define XS_CLR_UFLW    0x08    /* clear underflow */
-#define XS_CLR_COLL    0x04    /* clear collision */
-#define XS_CLR_16COLL  0x02    /* clear 16th collision */
-#define XS_CLR_PERR    0x01    /* clear parity error */
-
-/* bits in EDLC_XMASK, mask/enable transmit interrupts.  register is r/w */
-#define XM_TPOK                0x80    /* =1 to enable Xmt Pkt OK interrupts */
-#define XM_RCVD                0x20    /* =1 to enable Xmt Pkt Rcvd ints */
-#define XM_UFLW                0x08    /* =1 to enable Xmt Underflow ints */
-#define XM_COLL                0x04    /* =1 to enable Xmt Collision ints */
-#define XM_COLL16      0x02    /* =1 to enable Xmt 16th Coll ints */
-#define XM_PERR                0x01    /* =1 to enable Xmt Parity Error ints */
-                               /* note: always clear this bit */
-#define XM_ALL         (XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16)
-
-/* bits in EDLC_RSTAT, interrupt clear on write, status when read */
-#define RS_PKT_OK      0x80    /* received good packet */
-#define RS_RST_PKT     0x10    /* RESET packet received */
-#define RS_RUNT                0x08    /* Runt Pkt rcvd.  Len < 64 Bytes */
-#define RS_ALIGN       0x04    /* Alignment error. not 8 bit aligned */
-#define RS_CRC_ERR     0x02    /* Bad CRC on rcvd pkt */
-#define RS_OFLW                0x01    /* overflow for rcv FIFO */
-#define RS_VALID_BITS  ( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW )
-                               /* all valid RSTAT bits */
-
-#define RS_CLR_PKT_OK  0x80    /* clear rcvd packet interrupt */
-#define RS_CLR_RST_PKT 0x10    /* clear RESET packet received */
-#define RS_CLR_RUNT    0x08    /* clear Runt Pckt received */
-#define RS_CLR_ALIGN   0x04    /* clear Alignment error */
-#define RS_CLR_CRC_ERR 0x02    /* clear CRC error */
-#define RS_CLR_OFLW    0x01    /* clear rcv FIFO Overflow */
-
-/* bits in EDLC_RMASK, mask/enable receive interrupts.  register is r/w */
-#define RM_PKT_OK      0x80    /* =1 to enable rcvd good packet ints */
-#define RM_RST_PKT     0x10    /* =1 to enable RESET packet ints */
-#define RM_RUNT                0x08    /* =1 to enable Runt Pkt rcvd ints */
-#define RM_ALIGN       0x04    /* =1 to enable Alignment error ints */
-#define RM_CRC_ERR     0x02    /* =1 to enable Bad CRC error ints */
-#define RM_OFLW                0x01    /* =1 to enable overflow error ints */
-
-/* bits in EDLC_RMODE, set Receive Packet mode.  register is r/w */
-#define RMD_TEST       0x80    /* =1 for Chip testing.  normally 0 */
-#define RMD_ADD_SIZ    0x10    /* =1 5-byte addr match.  normally 0 */
-#define RMD_EN_RUNT    0x08    /* =1 enable runt rcv.  normally 0 */
-#define RMD_EN_RST     0x04    /* =1 to rcv RESET pkt.  normally 0 */
-
-#define RMD_PROMISC    0x03    /* receive *all* packets.  unusual */
-#define RMD_MULTICAST  0x02    /* receive multicasts too.  unusual */
-#define RMD_BROADCAST  0x01    /* receive broadcasts & normal. usual */
-#define RMD_NO_PACKETS 0x00    /* don't receive any packets. unusual */
-
-/* bits in EDLC_XMODE, set Transmit Packet mode.  register is r/w */
-#define XMD_COLL_CNT   0xf0    /* coll's since success.  read-only */
-#define XMD_IG_PAR     0x08    /* =1 to ignore parity.  ALWAYS set */
-#define XMD_T_MODE     0x04    /* =1 to power xcvr. ALWAYS set this */
-#define XMD_LBC                0x02    /* =1 for loopbakc.  normally set */
-#define XMD_DIS_C      0x01    /* =1 disables contention. normally 0 */
-
-/* bits in EDLC_RESET, write only */
-#define RS_RESET       0x80    /* =1 to hold EDLC in reset state */
-
-/* bits in IE_MMODE, write only */
-#define MM_EN_DMA      0x80    /* =1 begin DMA xfer, Cplt clrs it */
-#define MM_EN_RCV      0x40    /* =1 allows Pkt rcv.  clr'd by rcv */
-#define MM_EN_XMT      0x20    /* =1 begin Xmt pkt.  Cplt clrs it */
-#define MM_BUS_PAGE    0x18    /* =00 ALWAYS.  Used when MUX=1 */
-#define MM_NET_PAGE    0x06    /* =00 ALWAYS.  Used when MUX=0 */
-#define MM_MUX         0x01    /* =1 means Rcv Buff on system bus */
-                               /* =0 means Xmt Buff on system bus */
-
-/* bits in IE_ISTAT, read only */
-#define IS_TDIAG       0x80    /* =1 if Diagnostic problem */
-#define IS_EN_RCV      0x20    /* =1 until frame is rcv'd cplt */
-#define IS_EN_XMT      0x10    /* =1 until frame is xmt'd cplt */
-#define IS_EN_DMA      0x08    /* =1 until DMA is cplt or aborted */
-#define IS_DMA_INT     0x04    /* =0 iff DMA done interrupt. */
-#define IS_R_INT       0x02    /* =0 iff unmasked Rcv interrupt */
-#define IS_X_INT       0x01    /* =0 iff unmasked Xmt interrupt */
-
index 63c13125db6c9d0a58dcc70438d4af4058bcfd1e..34f76e99dc8ac4f0ca1029c82030e8f0791d07cd 100644 (file)
@@ -755,9 +755,6 @@ static void r6040_mac_address(struct net_device *dev)
        iowrite16(adrp[0], ioaddr + MID_0L);
        iowrite16(adrp[1], ioaddr + MID_0M);
        iowrite16(adrp[2], ioaddr + MID_0H);
-
-       /* Store MAC Address in perm_addr */
-       memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
 }
 
 static int r6040_open(struct net_device *dev)
@@ -957,9 +954,9 @@ static void netdev_get_drvinfo(struct net_device *dev,
 {
        struct r6040_private *rp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(rp->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1045,7 +1042,7 @@ static int r6040_mii_probe(struct net_device *dev)
        }
 
        phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
-                               0, PHY_INTERFACE_MODE_MII);
+                            PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
                dev_err(&lp->pdev->dev, "could not attach to PHY\n");
index 5ac93323a40cfa40995fbbaa3a4bc5ce0c3bea0a..b62a32484f6a629874413e045eb364b75d38d596 100644 (file)
@@ -1949,7 +1949,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        for (i = 0; i < 3; i++)
                ((__le16 *) (dev->dev_addr))[i] =
                    cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        dev->netdev_ops = &cp_netdev_ops;
        netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
index 5dc1616301277346f9d5a931d89c82b340470442..1276ac71353ae1c85d74da90ef83e2f2c31b9d8b 100644 (file)
@@ -991,7 +991,6 @@ static int rtl8139_init_one(struct pci_dev *pdev,
        for (i = 0; i < 3; i++)
                ((__le16 *) (dev->dev_addr))[i] =
                    cpu_to_le16(read_eeprom (ioaddr, i + 7, addr_len));
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        /* The Rtl8139-specific entries in the device structure. */
        dev->netdev_ops = &rtl8139_netdev_ops;
index 11702324a071b87deff9ef13f919be57e99b024b..4208f28d5d19f3124726baeb66d03b2d7d2e5bf2 100644 (file)
@@ -83,7 +83,7 @@ static const int multicast_filter_limit = 32;
 #define R8169_REGS_SIZE                256
 #define R8169_NAPI_WEIGHT      64
 #define NUM_TX_DESC    64      /* Number of Tx descriptor registers */
-#define NUM_RX_DESC    256     /* Number of Rx descriptor registers */
+#define NUM_RX_DESC    256U    /* Number of Rx descriptor registers */
 #define R8169_TX_RING_BYTES    (NUM_TX_DESC * sizeof(struct TxDesc))
 #define R8169_RX_RING_BYTES    (NUM_RX_DESC * sizeof(struct RxDesc))
 
@@ -727,7 +727,6 @@ struct rtl8169_private {
        u16 mac_version;
        u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
        u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
-       u32 dirty_rx;
        u32 dirty_tx;
        struct rtl8169_stats rx_stats;
        struct rtl8169_stats tx_stats;
@@ -4175,7 +4174,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
 
 static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
 {
-       tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
+       tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
 }
 
 static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
@@ -5918,7 +5917,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
                PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
 
        /* The infamous DAC f*ckup only happens at boot time */
-       if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
+       if ((tp->cp_cmd & PCIDAC) && !tp->cur_rx) {
                void __iomem *ioaddr = tp->mmio_addr;
 
                netif_info(tp, intr, dev, "disabling PCI DAC\n");
@@ -6033,10 +6032,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget
        unsigned int count;
 
        cur_rx = tp->cur_rx;
-       rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
-       rx_left = min(rx_left, budget);
 
-       for (; rx_left > 0; rx_left--, cur_rx++) {
+       for (rx_left = min(budget, NUM_RX_DESC); rx_left > 0; rx_left--, cur_rx++) {
                unsigned int entry = cur_rx % NUM_RX_DESC;
                struct RxDesc *desc = tp->RxDescArray + entry;
                u32 status;
@@ -6114,8 +6111,6 @@ release_descriptor:
        count = cur_rx - tp->cur_rx;
        tp->cur_rx = cur_rx;
 
-       tp->dirty_rx += count;
-
        return count;
 }
 
@@ -6939,7 +6934,6 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Get MAC address */
        for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
        dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
index 3d705862bd7d1176ec62235bc7fadc508b9dddbc..e195c1e89d6164670eae151bd9bec99b0951e3fe 100644 (file)
@@ -1422,7 +1422,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
 
        /* Try connect to PHY */
        phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
-                               0, mdp->phy_interface);
+                            mdp->phy_interface);
        if (IS_ERR(phydev)) {
                dev_err(&ndev->dev, "phy_connect failed\n");
                return PTR_ERR(phydev);
index 72fc57dd084d1a6b57a9301a8ae2bc43a3ffd249..21683e2b1ff412817213fa206416a6813235367d 100644 (file)
@@ -795,7 +795,7 @@ static inline int s6gmac_phy_start(struct net_device *dev)
        struct phy_device *p = NULL;
        while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i])))
                i++;
-       p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0,
+       p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link,
                        PHY_INTERFACE_MODE_RGMII);
        if (IS_ERR(p)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
index 29f18533fdc7663f6fe9552d629da322d5febb96..a71e1ec068ed3b45652a5a30613ec9de9f9fecac 100644 (file)
@@ -26,17 +26,6 @@ config ARM_ETHER3
          If you have an Acorn system with one of these network cards, you
          should say Y to this option if you wish to use it with Linux.
 
-config SEEQ8005
-       tristate "SEEQ8005 support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
-       ---help---
-         This is a driver for the SEEQ 8005 network (Ethernet) card.  If this
-         is for you, read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called seeq8005.
-
 config SGISEEQ
        tristate "SGI Seeq ethernet controller support"
        depends on SGI_HAS_SEEQ
index 3e258a580c0599f084564f4b2eb2b3392f966ff6..0488e99b831f7a64a22400a9afab0180b0d937c5 100644 (file)
@@ -3,5 +3,4 @@
 #
 
 obj-$(CONFIG_ARM_ETHER3) += ether3.o
-obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
diff --git a/drivers/net/ethernet/seeq/seeq8005.c b/drivers/net/ethernet/seeq/seeq8005.c
deleted file mode 100644 (file)
index d6e50de..0000000
+++ /dev/null
@@ -1,749 +0,0 @@
-/* seeq8005.c: A network driver for linux. */
-/*
-       Based on skeleton.c,
-       Written 1993-94 by Donald Becker.
-       See the skeleton.c file for further copyright information.
-
-       This software may be used and distributed according to the terms
-       of the GNU General Public License, incorporated herein by reference.
-
-       The author may be reached as hamish@zot.apana.org.au
-
-       This file is a network device driver for the SEEQ 8005 chipset and
-       the Linux operating system.
-
-*/
-
-static const char version[] =
-       "seeq8005.c:v1.00 8/07/95 Hamish Coleman (hamish@zot.apana.org.au)\n";
-
-/*
-  Sources:
-       SEEQ 8005 databook
-
-  Version history:
-       1.00    Public release. cosmetic changes (no warnings now)
-       0.68    Turning per- packet,interrupt debug messages off - testing for release.
-       0.67    timing problems/bad buffer reads seem to be fixed now
-       0.63    *!@$ protocol=eth_type_trans -- now packets flow
-       0.56    Send working
-       0.48    Receive working
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "seeq8005.h"
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int seeq8005_portlist[] __initdata =
-   { 0x300, 0x320, 0x340, 0x360, 0};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* Information that need to be kept for each board. */
-struct net_local {
-       unsigned short receive_ptr;             /* What address in packet memory do we expect a recv_pkt_header? */
-       long open_time;                         /* Useless example local info. */
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00
-#define SA_ADDR1 0x80
-#define SA_ADDR2 0x4b
-
-/* Index to functions, as function prototypes. */
-
-static int seeq8005_probe1(struct net_device *dev, int ioaddr);
-static int seeq8005_open(struct net_device *dev);
-static void seeq8005_timeout(struct net_device *dev);
-static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
-                                       struct net_device *dev);
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
-static void seeq8005_rx(struct net_device *dev);
-static int seeq8005_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-/* Example routines you must write ;->. */
-#define tx_done(dev)   (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
-static void hardware_send_packet(struct net_device *dev, char *buf, int length);
-extern void seeq8005_init(struct net_device *dev, int startp);
-static inline void wait_for_buffer(struct net_device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   */
-
-static int io = 0x320;
-static int irq = 10;
-
-struct net_device * __init seeq8005_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-       unsigned *port;
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-       }
-
-       if (io > 0x1ff) {       /* Check a single specified location. */
-               err = seeq8005_probe1(dev, io);
-       } else if (io != 0) {   /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-               for (port = seeq8005_portlist; *port; port++) {
-                       if (seeq8005_probe1(dev, *port) == 0)
-                               break;
-               }
-               if (!*port)
-                       err = -ENODEV;
-       }
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       release_region(dev->base_addr, SEEQ8005_IO_EXTENT);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static const struct net_device_ops seeq8005_netdev_ops = {
-       .ndo_open               = seeq8005_open,
-       .ndo_stop               = seeq8005_close,
-       .ndo_start_xmit         = seeq8005_send_packet,
-       .ndo_tx_timeout         = seeq8005_timeout,
-       .ndo_set_rx_mode        = set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/* This is the real probe routine.  Linux has a history of friendly device
-   probes on the ISA bus.  A good device probes avoids doing writes, and
-   verifies that the correct device exists and functions.  */
-
-static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
-{
-       static unsigned version_printed;
-       int i,j;
-       unsigned char SA_prom[32];
-       int old_cfg1;
-       int old_cfg2;
-       int old_stat;
-       int old_dmaar;
-       int old_rear;
-       int retval;
-
-       if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
-               return -ENODEV;
-
-       if (net_debug>1)
-               printk("seeq8005: probing at 0x%x\n",ioaddr);
-
-       old_stat = inw(SEEQ_STATUS);                                    /* read status register */
-       if (old_stat == 0xffff) {
-               retval = -ENODEV;
-               goto out;                                               /* assume that 0xffff == no device */
-       }
-       if ( (old_stat & 0x1800) != 0x1800 ) {                          /* assume that unused bits are 1, as my manual says */
-               if (net_debug>1) {
-                       printk("seeq8005: reserved stat bits != 0x1800\n");
-                       printk("          == 0x%04x\n",old_stat);
-               }
-               retval = -ENODEV;
-               goto out;
-       }
-
-       old_rear = inw(SEEQ_REA);
-       if (old_rear == 0xffff) {
-               outw(0,SEEQ_REA);
-               if (inw(SEEQ_REA) == 0xffff) {                          /* assume that 0xffff == no device */
-                       retval = -ENODEV;
-                       goto out;
-               }
-       } else if ((old_rear & 0xff00) != 0xff00) {                     /* assume that unused bits are 1 */
-               if (net_debug>1) {
-                       printk("seeq8005: unused rear bits != 0xff00\n");
-                       printk("          == 0x%04x\n",old_rear);
-               }
-               retval = -ENODEV;
-               goto out;
-       }
-
-       old_cfg2 = inw(SEEQ_CFG2);                                      /* read CFG2 register */
-       old_cfg1 = inw(SEEQ_CFG1);
-       old_dmaar = inw(SEEQ_DMAAR);
-
-       if (net_debug>4) {
-               printk("seeq8005: stat = 0x%04x\n",old_stat);
-               printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
-               printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
-               printk("seeq8005: raer = 0x%04x\n",old_rear);
-               printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
-       }
-
-       outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);      /* setup for reading PROM */
-       outw( 0, SEEQ_DMAAR);                                           /* set starting PROM address */
-       outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1);                         /* set buffer to look at PROM */
-
-
-       j=0;
-       for(i=0; i <32; i++) {
-               j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
-       }
-
-#if 0
-       /* untested because I only have the one card */
-       if ( (j&0xff) != 0 ) {                                          /* checksum appears to be 8bit = 0 */
-               if (net_debug>1) {                                      /* check this before deciding that we have a card */
-                       printk("seeq8005: prom sum error\n");
-               }
-               outw( old_stat, SEEQ_STATUS);
-               outw( old_dmaar, SEEQ_DMAAR);
-               outw( old_cfg1, SEEQ_CFG1);
-               retval = -ENODEV;
-               goto out;
-       }
-#endif
-
-       outw( SEEQCFG2_RESET, SEEQ_CFG2);                               /* reset the card */
-       udelay(5);
-       outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-
-       if (net_debug) {
-               printk("seeq8005: prom sum = 0x%08x\n",j);
-               for(j=0; j<32; j+=16) {
-                       printk("seeq8005: prom %02x: ",j);
-                       for(i=0;i<16;i++) {
-                               printk("%02x ",SA_prom[j|i]);
-                       }
-                       printk(" ");
-                       for(i=0;i<16;i++) {
-                               if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
-                                       printk("%c", SA_prom[j|i]);
-                               } else {
-                                       printk(" ");
-                               }
-                       }
-                       printk("\n");
-               }
-       }
-
-#if 0
-       /*
-        * testing the packet buffer memory doesn't work yet
-        * but all other buffer accesses do
-        *                      - fixing is not a priority
-        */
-       if (net_debug>1) {                                      /* test packet buffer memory */
-               printk("seeq8005: testing packet buffer ... ");
-               outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
-               outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-               outw( 0 , SEEQ_DMAAR);
-               for(i=0;i<32768;i++) {
-                       outw(0x5a5a, SEEQ_BUFFER);
-               }
-               j=jiffies+HZ;
-               while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
-                       mb();
-               outw( 0 , SEEQ_DMAAR);
-               while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
-                       mb();
-               if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
-                       outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
-               outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-               j=0;
-               for(i=0;i<32768;i++) {
-                       if (inw(SEEQ_BUFFER) != 0x5a5a)
-                               j++;
-               }
-               if (j) {
-                       printk("%i\n",j);
-               } else {
-                       printk("ok.\n");
-               }
-       }
-#endif
-
-       if (net_debug  &&  version_printed++ == 0)
-               printk(version);
-
-       printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
-
-       /* Fill in the 'dev' fields. */
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-
-       /* Retrieve and print the ethernet address. */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = SA_prom[i+6];
-       printk("%pM", dev->dev_addr);
-
-       if (dev->irq == 0xff)
-               ;                       /* Do nothing: a user-level program will set it. */
-       else if (dev->irq < 2) {        /* "Auto-IRQ" */
-               unsigned long cookie = probe_irq_on();
-
-               outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
-
-               dev->irq = probe_irq_off(cookie);
-
-               if (net_debug >= 2)
-                       printk(" autoirq is %d\n", dev->irq);
-       } else if (dev->irq == 2)
-         /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
-          * or don't know which one to set.
-          */
-         dev->irq = 9;
-
-#if 0
-       {
-                int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
-                if (irqval) {
-                        printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
-                                        dev->irq, irqval);
-                        retval = -EAGAIN;
-                        goto out;
-                }
-       }
-#endif
-       dev->netdev_ops = &seeq8005_netdev_ops;
-       dev->watchdog_timeo     = HZ/20;
-       dev->flags &= ~IFF_MULTICAST;
-
-       return 0;
-out:
-       release_region(ioaddr, SEEQ8005_IO_EXTENT);
-       return retval;
-}
-
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-   */
-static int seeq8005_open(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-
-       {
-                int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
-                if (irqval) {
-                        printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
-                                        dev->irq, irqval);
-                        return -EAGAIN;
-                }
-       }
-
-       /* Reset the hardware here.  Don't forget to set the station address. */
-       seeq8005_init(dev, 1);
-
-       lp->open_time = jiffies;
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-static void seeq8005_timeout(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
-                  tx_done(dev) ? "IRQ conflict" : "network cable problem");
-       /* Try to restart the adaptor. */
-       seeq8005_init(dev, 1);
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue(dev);
-}
-
-static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
-                                       struct net_device *dev)
-{
-       short length = skb->len;
-       unsigned char *buf;
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       return NETDEV_TX_OK;
-               length = ETH_ZLEN;
-       }
-       buf = skb->data;
-
-       /* Block a timer-based transmit from overlapping */
-       netif_stop_queue(dev);
-
-       hardware_send_packet(dev, buf, length);
-       dev->stats.tx_bytes += length;
-       dev_kfree_skb (skb);
-       /* You might need to clean up and record Tx statistics here. */
-
-       return NETDEV_TX_OK;
-}
-
-/*
- * wait_for_buffer
- *
- * This routine waits for the SEEQ chip to assert that the FIFO is ready
- * by checking for a window interrupt, and then clearing it. This has to
- * occur in the interrupt handler!
- */
-inline void wait_for_buffer(struct net_device * dev)
-{
-       int ioaddr = dev->base_addr;
-       unsigned long tmp;
-       int status;
-
-       tmp = jiffies + HZ;
-       while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
-               cpu_relax();
-
-       if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
-               outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-}
-
-/* The typical workload of the driver:
-   Handle the network interface interrupts. */
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct net_local *lp;
-       int ioaddr, status, boguscount = 0;
-       int handled = 0;
-
-       ioaddr = dev->base_addr;
-       lp = netdev_priv(dev);
-
-       status = inw(SEEQ_STATUS);
-       do {
-               if (net_debug >2) {
-                       printk("%s: int, status=0x%04x\n",dev->name,status);
-               }
-
-               if (status & SEEQSTAT_WINDOW_INT) {
-                       handled = 1;
-                       outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-                       if (net_debug) {
-                               printk("%s: window int!\n",dev->name);
-                       }
-               }
-               if (status & SEEQSTAT_TX_INT) {
-                       handled = 1;
-                       outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-                       dev->stats.tx_packets++;
-                       netif_wake_queue(dev);  /* Inform upper layers. */
-               }
-               if (status & SEEQSTAT_RX_INT) {
-                       handled = 1;
-                       /* Got a packet(s). */
-                       seeq8005_rx(dev);
-               }
-               status = inw(SEEQ_STATUS);
-       } while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
-
-       if(net_debug>2) {
-               printk("%s: eoi\n",dev->name);
-       }
-       return IRQ_RETVAL(handled);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void seeq8005_rx(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int boguscount = 10;
-       int pkt_hdr;
-       int ioaddr = dev->base_addr;
-
-       do {
-               int next_packet;
-               int pkt_len;
-               int i;
-               int status;
-
-               status = inw(SEEQ_STATUS);
-               outw( lp->receive_ptr, SEEQ_DMAAR);
-               outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-               wait_for_buffer(dev);
-               next_packet = ntohs(inw(SEEQ_BUFFER));
-               pkt_hdr = inw(SEEQ_BUFFER);
-
-               if (net_debug>2) {
-                       printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
-               }
-
-               if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) {    /* Read all the frames? */
-                       return;                                                 /* Done for now */
-               }
-
-               if ((pkt_hdr & SEEQPKTS_DONE)==0)
-                       break;
-
-               if (next_packet < lp->receive_ptr) {
-                       pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
-               } else {
-                       pkt_len = next_packet - lp->receive_ptr - 4;
-               }
-
-               if (next_packet < ((DEFAULT_TEA+1)<<8)) {                       /* is the next_packet address sane? */
-                       printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
-                       seeq8005_init(dev,1);
-                       return;
-               }
-
-               lp->receive_ptr = next_packet;
-
-               if (net_debug>2) {
-                       printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
-               }
-
-               if (pkt_hdr & SEEQPKTS_ANY_ERROR) {                             /* There was an error. */
-                       dev->stats.rx_errors++;
-                       if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
-                       if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
-                       if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
-                       if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
-                       /* skip over this packet */
-                       outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-                       outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
-               } else {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-                       unsigned char *buf;
-
-                       skb = netdev_alloc_skb(dev, pkt_len);
-                       if (skb == NULL) {
-                               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-                               dev->stats.rx_dropped++;
-                               break;
-                       }
-                       skb_reserve(skb, 2);    /* align data on 16 byte */
-                       buf = skb_put(skb,pkt_len);
-
-                       insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
-
-                       if (net_debug>2) {
-                               char * p = buf;
-                               printk("%s: recv ",dev->name);
-                               for(i=0;i<14;i++) {
-                                       printk("%02x ",*(p++)&0xff);
-                               }
-                               printk("\n");
-                       }
-
-                       skb->protocol=eth_type_trans(skb,dev);
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-               }
-       } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
-
-       /* If any worth-while packets have been received, netif_rx()
-          has done a mark_bh(NET_BH) for us and will work on them
-          when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to net_open(). */
-static int seeq8005_close(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-
-       lp->open_time = 0;
-
-       netif_stop_queue(dev);
-
-       /* Flush the Tx and disable Rx here. */
-       outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-
-       free_irq(dev->irq, dev);
-
-       /* Update the statistics here. */
-
-       return 0;
-
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1     Promiscuous mode, receive all packets
-   num_addrs == 0      Normal mode, clear multicast list
-   num_addrs > 0       Multicast mode, receive normal and MC packets, and do
-                       best-effort filtering.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-/*
- * I _could_ do up to 6 addresses here, but won't (yet?)
- */
-
-#if 0
-       int ioaddr = dev->base_addr;
-/*
- * hmm, not even sure if my matching works _anyway_ - seem to be receiving
- * _everything_ . . .
- */
-
-       if (num_addrs) {                        /* Enable promiscuous mode */
-               outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL,  SEEQ_CFG1);
-               dev->flags|=IFF_PROMISC;
-       } else {                                /* Disable promiscuous mode, use normal mode */
-               outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
-       }
-#endif
-}
-
-void seeq8005_init(struct net_device *dev, int startp)
-{
-       struct net_local *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int i;
-
-       outw(SEEQCFG2_RESET, SEEQ_CFG2);        /* reset device */
-       udelay(5);
-
-       outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-       outw( 0, SEEQ_DMAAR);                   /* load start address into both low and high byte */
-/*     wait_for_buffer(dev); */                /* I think that you only need a wait for memory buffer */
-       outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
-       for(i=0;i<6;i++) {                      /* set Station address */
-               outb(dev->dev_addr[i], SEEQ_BUFFER);
-               udelay(2);
-       }
-
-       outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1);  /* set xmit end area pointer to 16K */
-       outb( DEFAULT_TEA, SEEQ_BUFFER);        /* this gives us 16K of send buffer and 48K of recv buffer */
-
-       lp->receive_ptr = (DEFAULT_TEA+1)<<8;   /* so we can find our packet_header */
-       outw( lp->receive_ptr, SEEQ_RPR);       /* Receive Pointer Register is set to recv buffer memory */
-
-       outw( 0x00ff, SEEQ_REA);                /* Receive Area End */
-
-       if (net_debug>4) {
-               printk("%s: SA0 = ",dev->name);
-
-               outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-               outw( 0, SEEQ_DMAAR);
-               outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
-               for(i=0;i<6;i++) {
-                       printk("%02x ",inb(SEEQ_BUFFER));
-               }
-               printk("\n");
-       }
-
-       outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
-       outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
-       outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
-
-       if (net_debug>4) {
-               int old_cfg1;
-               old_cfg1 = inw(SEEQ_CFG1);
-               printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
-               printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
-               printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
-               printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
-               printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
-
-       }
-}
-
-
-static void hardware_send_packet(struct net_device * dev, char *buf, int length)
-{
-       int ioaddr = dev->base_addr;
-       int status = inw(SEEQ_STATUS);
-       int transmit_ptr = 0;
-       unsigned long tmp;
-
-       if (net_debug>4) {
-               printk("%s: send 0x%04x\n",dev->name,length);
-       }
-
-       /* Set FIFO to writemode and set packet-buffer address */
-       outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-       outw( transmit_ptr, SEEQ_DMAAR);
-
-       /* output SEEQ Packet header barfage */
-       outw( htons(length + 4), SEEQ_BUFFER);
-       outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
-
-       /* blat the buffer */
-       outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
-       /* paranoia !! */
-       outw( 0, SEEQ_BUFFER);
-       outw( 0, SEEQ_BUFFER);
-
-       /* set address of start of transmit chain */
-       outw( transmit_ptr, SEEQ_TPR);
-
-       /* drain FIFO */
-       tmp = jiffies;
-       while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
-               mb();
-
-       /* doit ! */
-       outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-
-}
-
-
-#ifdef MODULE
-
-static struct net_device *dev_seeq;
-MODULE_LICENSE("GPL");
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
-MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
-
-int __init init_module(void)
-{
-       dev_seeq = seeq8005_probe(-1);
-       return PTR_RET(dev_seeq);
-}
-
-void __exit cleanup_module(void)
-{
-       unregister_netdev(dev_seeq);
-       release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT);
-       free_netdev(dev_seeq);
-}
-
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/seeq/seeq8005.h b/drivers/net/ethernet/seeq/seeq8005.h
deleted file mode 100644 (file)
index 5dfb009..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * defines, etc for the seeq8005
- */
-
-/*
- * This file is distributed under GPL.
- *
- * This style and layout of this file is also copied
- * from many of the other linux network device drivers.
- */
-
-/* The number of low I/O ports used by the ethercard. */
-#define SEEQ8005_IO_EXTENT     16
-
-#define SEEQ_B         (ioaddr)
-
-#define        SEEQ_CMD        (SEEQ_B)                /* Write only */
-#define        SEEQ_STATUS     (SEEQ_B)                /* Read only */
-#define SEEQ_CFG1      (SEEQ_B + 2)
-#define SEEQ_CFG2      (SEEQ_B + 4)
-#define        SEEQ_REA        (SEEQ_B + 6)            /* Receive End Area Register */
-#define SEEQ_RPR       (SEEQ_B + 10)           /* Receive Pointer Register */
-#define        SEEQ_TPR        (SEEQ_B + 12)           /* Transmit Pointer Register */
-#define        SEEQ_DMAAR      (SEEQ_B + 14)           /* DMA Address Register */
-#define SEEQ_BUFFER    (SEEQ_B + 8)            /* Buffer Window Register */
-
-#define        DEFAULT_TEA     (0x3f)
-
-#define SEEQCMD_DMA_INT_EN     (0x0001)        /* DMA Interrupt Enable */
-#define SEEQCMD_RX_INT_EN      (0x0002)        /* Receive Interrupt Enable */
-#define SEEQCMD_TX_INT_EN      (0x0004)        /* Transmit Interrupt Enable */
-#define SEEQCMD_WINDOW_INT_EN  (0x0008)        /* What the hell is this for?? */
-#define SEEQCMD_INT_MASK       (0x000f)
-
-#define SEEQCMD_DMA_INT_ACK    (0x0010)        /* DMA ack */
-#define SEEQCMD_RX_INT_ACK     (0x0020)
-#define SEEQCMD_TX_INT_ACK     (0x0040)
-#define        SEEQCMD_WINDOW_INT_ACK  (0x0080)
-#define SEEQCMD_ACK_ALL                (0x00f0)
-
-#define SEEQCMD_SET_DMA_ON     (0x0100)        /* Enables DMA Request logic */
-#define SEEQCMD_SET_RX_ON      (0x0200)        /* Enables Packet RX */
-#define SEEQCMD_SET_TX_ON      (0x0400)        /* Starts TX run */
-#define SEEQCMD_SET_DMA_OFF    (0x0800)
-#define SEEQCMD_SET_RX_OFF     (0x1000)
-#define SEEQCMD_SET_TX_OFF     (0x2000)
-#define SEEQCMD_SET_ALL_OFF    (0x3800)        /* set all logic off */
-
-#define SEEQCMD_FIFO_READ      (0x4000)        /* Set FIFO to read mode (read from Buffer) */
-#define SEEQCMD_FIFO_WRITE     (0x8000)        /* Set FIFO to write mode */
-
-#define SEEQSTAT_DMA_INT_EN    (0x0001)        /* Status of interrupt enable */
-#define SEEQSTAT_RX_INT_EN     (0x0002)
-#define SEEQSTAT_TX_INT_EN     (0x0004)
-#define SEEQSTAT_WINDOW_INT_EN (0x0008)
-
-#define        SEEQSTAT_DMA_INT        (0x0010)        /* Interrupt flagged */
-#define SEEQSTAT_RX_INT                (0x0020)
-#define SEEQSTAT_TX_INT                (0x0040)
-#define        SEEQSTAT_WINDOW_INT     (0x0080)
-#define SEEQSTAT_ANY_INT       (0x00f0)
-
-#define SEEQSTAT_DMA_ON                (0x0100)        /* DMA logic on */
-#define SEEQSTAT_RX_ON         (0x0200)        /* Packet RX on */
-#define SEEQSTAT_TX_ON         (0x0400)        /* TX running */
-
-#define SEEQSTAT_FIFO_FULL     (0x2000)
-#define SEEQSTAT_FIFO_EMPTY    (0x4000)
-#define SEEQSTAT_FIFO_DIR      (0x8000)        /* 1=read, 0=write */
-
-#define SEEQCFG1_BUFFER_MASK   (0x000f)        /* define what maps into the BUFFER register */
-#define SEEQCFG1_BUFFER_MAC0   (0x0000)        /* MAC station addresses 0-5 */
-#define SEEQCFG1_BUFFER_MAC1   (0x0001)
-#define SEEQCFG1_BUFFER_MAC2   (0x0002)
-#define SEEQCFG1_BUFFER_MAC3   (0x0003)
-#define SEEQCFG1_BUFFER_MAC4   (0x0004)
-#define SEEQCFG1_BUFFER_MAC5   (0x0005)
-#define SEEQCFG1_BUFFER_PROM   (0x0006)        /* The Address/CFG PROM */
-#define SEEQCFG1_BUFFER_TEA    (0x0007)        /* Transmit end area */
-#define SEEQCFG1_BUFFER_BUFFER (0x0008)        /* Packet buffer memory */
-#define SEEQCFG1_BUFFER_INT_VEC        (0x0009)        /* Interrupt Vector */
-
-#define SEEQCFG1_DMA_INTVL_MASK        (0x0030)
-#define SEEQCFG1_DMA_CONT      (0x0000)
-#define SEEQCFG1_DMA_800ns     (0x0010)
-#define SEEQCFG1_DMA_1600ns    (0x0020)
-#define SEEQCFG1_DMA_3200ns    (0x0030)
-
-#define SEEQCFG1_DMA_LEN_MASK  (0x00c0)
-#define SEEQCFG1_DMA_LEN1      (0x0000)
-#define SEEQCFG1_DMA_LEN2      (0x0040)
-#define SEEQCFG1_DMA_LEN4      (0x0080)
-#define SEEQCFG1_DMA_LEN8      (0x00c0)
-
-#define SEEQCFG1_MAC_MASK      (0x3f00)        /* Dis/enable bits for MAC addresses */
-#define SEEQCFG1_MAC0_EN       (0x0100)
-#define SEEQCFG1_MAC1_EN       (0x0200)
-#define SEEQCFG1_MAC2_EN       (0x0400)
-#define SEEQCFG1_MAC3_EN       (0x0800)
-#define        SEEQCFG1_MAC4_EN        (0x1000)
-#define SEEQCFG1_MAC5_EN       (0x2000)
-
-#define        SEEQCFG1_MATCH_MASK     (0xc000)        /* Packet matching logic cfg bits */
-#define SEEQCFG1_MATCH_SPECIFIC        (0x0000)        /* only matching MAC addresses */
-#define SEEQCFG1_MATCH_BROAD   (0x4000)        /* matching and broadcast addresses */
-#define SEEQCFG1_MATCH_MULTI   (0x8000)        /* matching, broadcast and multicast */
-#define SEEQCFG1_MATCH_ALL     (0xc000)        /* Promiscuous mode */
-
-#define SEEQCFG1_DEFAULT       (SEEQCFG1_BUFFER_BUFFER | SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD)
-
-#define SEEQCFG2_BYTE_SWAP     (0x0001)        /* 0=Intel byte-order */
-#define SEEQCFG2_AUTO_REA      (0x0002)        /* if set, Receive End Area will be updated when reading from Buffer */
-
-#define SEEQCFG2_CRC_ERR_EN    (0x0008)        /* enables receiving of packets with CRC errors */
-#define SEEQCFG2_DRIBBLE_EN    (0x0010)        /* enables receiving of non-aligned packets */
-#define SEEQCFG2_SHORT_EN      (0x0020)        /* enables receiving of short packets */
-
-#define        SEEQCFG2_SLOTSEL        (0x0040)        /* 0= standard IEEE802.3, 1= smaller,faster, non-standard */
-#define SEEQCFG2_NO_PREAM      (0x0080)        /* 1= user supplies Xmit preamble bytes */
-#define SEEQCFG2_ADDR_LEN      (0x0100)        /* 1= 2byte addresses */
-#define SEEQCFG2_REC_CRC       (0x0200)        /* 0= received packets will have CRC stripped from them */
-#define SEEQCFG2_XMIT_NO_CRC   (0x0400)        /* don't xmit CRC with each packet (user supplies it) */
-#define SEEQCFG2_LOOPBACK      (0x0800)
-#define SEEQCFG2_CTRLO         (0x1000)
-#define SEEQCFG2_RESET         (0x8000)        /* software Hard-reset bit */
-
-struct seeq_pkt_hdr {
-       unsigned short  next;                   /* address of next packet header */
-       unsigned char   babble_int:1,           /* enable int on >1514 byte packet */
-                       coll_int:1,             /* enable int on collision */
-                       coll_16_int:1,          /* enable int on >15 collision */
-                       xmit_int:1,             /* enable int on success (or xmit with <15 collision) */
-                       unused:1,
-                       data_follows:1,         /* if not set, process this as a header and pointer only */
-                       chain_cont:1,           /* if set, more headers in chain                only cmd bit valid in recv header */
-                       xmit_recv:1;            /* if set, a xmit packet, else a receive packet.*/
-       unsigned char   status;
-};
-
-#define SEEQPKTH_BAB_INT_EN    (0x01)          /* xmit only */
-#define SEEQPKTH_COL_INT_EN    (0x02)          /* xmit only */
-#define SEEQPKTH_COL16_INT_EN  (0x04)          /* xmit only */
-#define SEEQPKTH_XMIT_INT_EN   (0x08)          /* xmit only */
-#define SEEQPKTH_DATA_FOLLOWS  (0x20)          /* supposedly in xmit only */
-#define SEEQPKTH_CHAIN         (0x40)          /* more headers follow */
-#define SEEQPKTH_XMIT          (0x80)
-
-#define SEEQPKTS_BABBLE                (0x0100)        /* xmit only */
-#define SEEQPKTS_OVERSIZE      (0x0100)        /* recv only */
-#define SEEQPKTS_COLLISION     (0x0200)        /* xmit only */
-#define SEEQPKTS_CRC_ERR       (0x0200)        /* recv only */
-#define SEEQPKTS_COLL16                (0x0400)        /* xmit only */
-#define SEEQPKTS_DRIB          (0x0400)        /* recv only */
-#define SEEQPKTS_SHORT         (0x0800)        /* recv only */
-#define SEEQPKTS_DONE          (0x8000)
-#define SEEQPKTS_ANY_ERROR     (0x0f00)
index 0767043f44a42866d545a8ff843604a3d717af48..3f93624fc27313134fa0682bc67cf154d8af0a31 100644 (file)
@@ -1439,7 +1439,7 @@ static int efx_phc_settime(struct ptp_clock_info *ptp,
 
        delta = timespec_sub(*e_ts, time_now);
 
-       efx_phc_adjtime(ptp, timespec_to_ns(&delta));
+       rc = efx_phc_adjtime(ptp, timespec_to_ns(&delta));
        if (rc != 0)
                return rc;
 
index dc171b4961e47f2a0b0b3247701da908d1dbd601..7ed08c32a9c512621665d14566e3371f24108398 100644 (file)
@@ -1565,9 +1565,9 @@ static void ioc3_get_drvinfo (struct net_device *dev,
 {
        struct ioc3_private *ip = netdev_priv(dev);
 
-        strcpy (info->driver, IOC3_NAME);
-        strcpy (info->version, IOC3_VERSION);
-        strcpy (info->bus_info, pci_name(ip->pdev));
+       strlcpy(info->driver, IOC3_NAME, sizeof(info->driver));
+       strlcpy(info->version, IOC3_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(ip->pdev), sizeof(info->bus_info));
 }
 
 static int ioc3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index b2315324cc6d77cbd97195b923bbb4952b1d5bc5..28f7268f1b8802eed15756784b5d68f298a7976a 100644 (file)
@@ -1458,12 +1458,12 @@ static int sc92031_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        mac0 = ioread32(port_base + MAC0);
        mac1 = ioread32(port_base + MAC0 + 4);
-       dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
-       dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
-       dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
-       dev->dev_addr[3] = dev->perm_addr[3] = mac0;
-       dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
-       dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+       dev->dev_addr[0] = mac0 >> 24;
+       dev->dev_addr[1] = mac0 >> 16;
+       dev->dev_addr[2] = mac0 >> 8;
+       dev->dev_addr[3] = mac0;
+       dev->dev_addr[4] = mac1 >> 8;
+       dev->dev_addr[5] = mac1;
 
        err = register_netdev(dev);
        if (err < 0)
index 5bffd9749a58e0e658a7413cf39ea7d21697756e..efca14eaefa9324487e3a0aa496730145920795d 100644 (file)
@@ -247,8 +247,7 @@ static const struct ethtool_ops sis900_ethtool_ops;
  *     @net_dev: the net device to get address for
  *
  *     Older SiS900 and friends, use EEPROM to store MAC address.
- *     MAC address is read from read_eeprom() into @net_dev->dev_addr and
- *     @net_dev->perm_addr.
+ *     MAC address is read from read_eeprom() into @net_dev->dev_addr.
  */
 
 static int sis900_get_mac_addr(struct pci_dev *pci_dev,
@@ -271,9 +270,6 @@ static int sis900_get_mac_addr(struct pci_dev *pci_dev,
        for (i = 0; i < 3; i++)
                ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
 
-       /* Store MAC Address in perm_addr */
-       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
        return 1;
 }
 
@@ -284,8 +280,7 @@ static int sis900_get_mac_addr(struct pci_dev *pci_dev,
  *
  *     SiS630E model, use APC CMOS RAM to store MAC address.
  *     APC CMOS RAM is accessed through ISA bridge.
- *     MAC address is read into @net_dev->dev_addr and
- *     @net_dev->perm_addr.
+ *     MAC address is read into @net_dev->dev_addr.
  */
 
 static int sis630e_get_mac_addr(struct pci_dev *pci_dev,
@@ -311,9 +306,6 @@ static int sis630e_get_mac_addr(struct pci_dev *pci_dev,
                ((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
        }
 
-       /* Store MAC Address in perm_addr */
-       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
        pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40);
        pci_dev_put(isa_bridge);
 
@@ -328,7 +320,7 @@ static int sis630e_get_mac_addr(struct pci_dev *pci_dev,
  *
  *     SiS635 model, set MAC Reload Bit to load Mac address from APC
  *     to rfdr. rfdr is accessed through rfcr. MAC address is read into
- *     @net_dev->dev_addr and @net_dev->perm_addr.
+ *     @net_dev->dev_addr.
  */
 
 static int sis635_get_mac_addr(struct pci_dev *pci_dev,
@@ -353,9 +345,6 @@ static int sis635_get_mac_addr(struct pci_dev *pci_dev,
                *( ((u16 *)net_dev->dev_addr) + i) = sr16(rfdr);
        }
 
-       /* Store MAC Address in perm_addr */
-       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
        /* enable packet filtering */
        sw32(rfcr, rfcrSave | RFEN);
 
@@ -375,7 +364,7 @@ static int sis635_get_mac_addr(struct pci_dev *pci_dev,
  *     EEDONE signal to refuse EEPROM access by LAN.
  *     The EEPROM map of SiS962 or SiS963 is different to SiS900.
  *     The signature field in SiS962 or SiS963 spec is meaningless.
- *     MAC address is read into @net_dev->dev_addr and @net_dev->perm_addr.
+ *     MAC address is read into @net_dev->dev_addr.
  */
 
 static int sis96x_get_mac_addr(struct pci_dev *pci_dev,
@@ -395,9 +384,6 @@ static int sis96x_get_mac_addr(struct pci_dev *pci_dev,
                        for (i = 0; i < 3; i++)
                                mac[i] = read_eeprom(ioaddr, i + EEPROMMACAddr);
 
-                       /* Store MAC Address in perm_addr */
-                       memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
                        rc = 1;
                        break;
                }
index 59a6f88da8676154b34526aa42c0feb34314a014..9dd842dbb8598b9d7825637238ce2d64aaa53f4a 100644 (file)
@@ -1522,9 +1522,10 @@ smc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void
 smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, CARDNAME, sizeof(info->driver));
-       strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+       strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+       strlcpy(info->version, version, sizeof(info->version));
+       strlcpy(info->bus_info, dev_name(dev->dev.parent),
+               sizeof(info->bus_info));
 }
 
 static int smc911x_ethtool_nwayreset(struct net_device *dev)
@@ -2035,7 +2036,7 @@ static int smc911x_drv_probe(struct platform_device *pdev)
        struct net_device *ndev;
        struct resource *res;
        struct smc911x_local *lp;
-       unsigned int *addr;
+       void __iomem *addr;
        int ret;
 
        DBG(SMC_DEBUG_FUNC, "--> %s\n",  __func__);
index a670d23d9340245ddcd4d573777c6c53151acb41..591650a8de3887942b4efeb78faa3e5ae3324039 100644 (file)
@@ -1597,9 +1597,10 @@ smc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void
 smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, CARDNAME, sizeof(info->driver));
-       strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+       strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+       strlcpy(info->version, version, sizeof(info->version));
+       strlcpy(info->bus_info, dev_name(dev->dev.parent),
+               sizeof(info->bus_info));
 }
 
 static int smc_ethtool_nwayreset(struct net_device *dev)
index e112877d15d3288c1f04e577501bd960faf9aa67..da5cc9a3b34cb3571740d0851569b6b89d236a41 100644 (file)
@@ -997,9 +997,8 @@ static int smsc911x_mii_probe(struct net_device *dev)
        SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X",
                   phydev->addr, phydev->phy_id);
 
-       ret = phy_connect_direct(dev, phydev,
-                       &smsc911x_phy_adjust_link, 0,
-                       pdata->config.phy_interface);
+       ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link,
+                                pdata->config.phy_interface);
 
        if (ret) {
                netdev_err(dev, "Could not attach to PHY\n");
@@ -1831,7 +1830,6 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 
        spin_lock_irq(&pdata->mac_lock);
index 3c586585e1b3f62d3b1eaab29d3bdcbaf4fa6b65..ecfb43614d7b8d2f11ce027a90c3a2e3ddb0785c 100644 (file)
@@ -1179,7 +1179,7 @@ static int smsc9420_mii_probe(struct net_device *dev)
                phydev->phy_id);
 
        phydev = phy_connect(dev, dev_name(&phydev->dev),
-               smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+                            smsc9420_phy_adjust_link, PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
                pr_err("%s: Could not attach to PHY\n", dev->name);
index 1372ce210b58b60aa32325b08a8da2d93b5abb6e..d1ac39c1b05d2894ceaee0ed41aeb49f03b88a04 100644 (file)
@@ -210,8 +210,7 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
                strlcpy(info->driver, MAC100_ETHTOOL_NAME,
                        sizeof(info->driver));
 
-       strcpy(info->version, DRV_MODULE_VERSION);
-       info->fw_version[0] = '\0';
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int stmmac_ethtool_getsettings(struct net_device *dev,
index f07c0612abf6843ffe7b41a8ecc2623aff42298f..8c657294ce565d71e2fdc23e6af16a649dc7da4d 100644 (file)
@@ -428,8 +428,7 @@ static int stmmac_init_phy(struct net_device *dev)
                 priv->plat->phy_addr);
        pr_debug("stmmac_init_phy:  trying to attach to %s\n", phy_id_fmt);
 
-       phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, 0,
-                            interface);
+       phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface);
 
        if (IS_ERR(phydev)) {
                pr_err("%s: Could not attach to PHY\n", dev->name);
index a0bdf077946614e50fcf30379d18c8192767b6f9..c8c491564f9ddf70b942b01a6b40f2346fe68f41 100644 (file)
@@ -8366,14 +8366,12 @@ static void niu_pci_vpd_validate(struct niu *np)
                return;
        }
 
-       memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN);
+       memcpy(dev->dev_addr, vpd->local_mac, ETH_ALEN);
 
-       val8 = dev->perm_addr[5];
-       dev->perm_addr[5] += np->port;
-       if (dev->perm_addr[5] < val8)
-               dev->perm_addr[4]++;
-
-       memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+       val8 = dev->dev_addr[5];
+       dev->dev_addr[5] += np->port;
+       if (dev->dev_addr[5] < val8)
+               dev->dev_addr[4]++;
 }
 
 static int niu_pci_probe_sprom(struct niu *np)
@@ -8470,29 +8468,27 @@ static int niu_pci_probe_sprom(struct niu *np)
        val = nr64(ESPC_MAC_ADDR0);
        netif_printk(np, probe, KERN_DEBUG, np->dev,
                     "SPROM: MAC_ADDR0[%08llx]\n", (unsigned long long)val);
-       dev->perm_addr[0] = (val >>  0) & 0xff;
-       dev->perm_addr[1] = (val >>  8) & 0xff;
-       dev->perm_addr[2] = (val >> 16) & 0xff;
-       dev->perm_addr[3] = (val >> 24) & 0xff;
+       dev->dev_addr[0] = (val >>  0) & 0xff;
+       dev->dev_addr[1] = (val >>  8) & 0xff;
+       dev->dev_addr[2] = (val >> 16) & 0xff;
+       dev->dev_addr[3] = (val >> 24) & 0xff;
 
        val = nr64(ESPC_MAC_ADDR1);
        netif_printk(np, probe, KERN_DEBUG, np->dev,
                     "SPROM: MAC_ADDR1[%08llx]\n", (unsigned long long)val);
-       dev->perm_addr[4] = (val >>  0) & 0xff;
-       dev->perm_addr[5] = (val >>  8) & 0xff;
+       dev->dev_addr[4] = (val >>  0) & 0xff;
+       dev->dev_addr[5] = (val >>  8) & 0xff;
 
-       if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+       if (!is_valid_ether_addr(&dev->dev_addr[0])) {
                dev_err(np->device, "SPROM MAC address invalid [ %pM ]\n",
-                       dev->perm_addr);
+                       dev->dev_addr);
                return -EINVAL;
        }
 
-       val8 = dev->perm_addr[5];
-       dev->perm_addr[5] += np->port;
-       if (dev->perm_addr[5] < val8)
-               dev->perm_addr[4]++;
-
-       memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+       val8 = dev->dev_addr[5];
+       dev->dev_addr[5] += np->port;
+       if (dev->dev_addr[5] < val8)
+               dev->dev_addr[4]++;
 
        val = nr64(ESPC_MOD_STR_LEN);
        netif_printk(np, probe, KERN_DEBUG, np->dev,
@@ -9267,16 +9263,14 @@ static int niu_get_of_props(struct niu *np)
                netdev_err(dev, "%s: OF MAC address prop len (%d) is wrong\n",
                           dp->full_name, prop_len);
        }
-       memcpy(dev->perm_addr, mac_addr, dev->addr_len);
-       if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+       memcpy(dev->dev_addr, mac_addr, dev->addr_len);
+       if (!is_valid_ether_addr(&dev->dev_addr[0])) {
                netdev_err(dev, "%s: OF MAC address is invalid\n",
                           dp->full_name);
-               netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->perm_addr);
+               netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->dev_addr);
                return -EINVAL;
        }
 
-       memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
-
        model = of_get_property(dp, "model", &prop_len);
 
        if (model)
index be82f6d13c5199228053ca37a69f847821542f35..5fafca0653051d3960fc5240341ad0271ffeb832 100644 (file)
@@ -1042,8 +1042,8 @@ static void bigmac_set_multicast(struct net_device *dev)
 /* Ethtool support... */
 static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "sunbmac");
-       strcpy(info->version, "2.0");
+       strlcpy(info->driver, "sunbmac", sizeof(info->driver));
+       strlcpy(info->version, "2.0", sizeof(info->version));
 }
 
 static u32 bigmac_get_link(struct net_device *dev)
index 1dcee6915843cd67f11169eab68c36fbbeb51a4c..49bf3e2eb652316757e2781ef7e703171c868414 100644 (file)
@@ -685,13 +685,14 @@ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        struct sunqe *qep = netdev_priv(dev);
        struct platform_device *op;
 
-       strcpy(info->driver, "sunqe");
-       strcpy(info->version, "3.0");
+       strlcpy(info->driver, "sunqe", sizeof(info->driver));
+       strlcpy(info->version, "3.0", sizeof(info->version));
 
        op = qep->op;
        regs = of_get_property(op->dev.of_node, "reg", NULL);
        if (regs)
-               sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+               snprintf(info->bus_info, sizeof(info->bus_info), "SBUS:%d",
+                        regs->which_io);
 
 }
 
index e1b8955308277fae7c953274492e3d9eb936f961..289b4eefb42f833500706b2e0f88eceb5bec800a 100644 (file)
@@ -882,8 +882,8 @@ static int vnet_set_mac_addr(struct net_device *dev, void *p)
 static void vnet_get_drvinfo(struct net_device *dev,
                             struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static u32 vnet_get_msglevel(struct net_device *dev)
@@ -1032,8 +1032,6 @@ static struct vnet *vnet_new(const u64 *local_mac)
        for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
 
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
        vp = netdev_priv(dev);
 
        spin_lock_init(&vp->lock);
index 1e4d743ff03e7b86e0cd72002166f0dc28212b73..e15cc71b826de613ad6e304480306f903e9e6e2c 100644 (file)
@@ -2179,10 +2179,10 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
 {
        struct bdx_priv *priv = netdev_priv(netdev);
 
-       strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
-       strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
-       strlcat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
-       strlcat(drvinfo->bus_info, pci_name(priv->pdev),
+       strlcpy(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(priv->pdev),
                sizeof(drvinfo->bus_info));
 
        drvinfo->n_stats = ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0);
index d9625f62b026cd06bbfdff222af8950b90bd3027..31bbbca341a7d5cb447c8be546bf44d04a97fc5e 100644 (file)
@@ -904,10 +904,9 @@ static int cpmac_set_ringparam(struct net_device *dev,
 static void cpmac_get_drvinfo(struct net_device *dev,
                              struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "cpmac");
-       strcpy(info->version, CPMAC_VERSION);
-       info->fw_version[0] = '\0';
-       sprintf(info->bus_info, "%s", "cpmac");
+       strlcpy(info->driver, "cpmac", sizeof(info->driver));
+       strlcpy(info->version, CPMAC_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info), "%s", "cpmac");
        info->regdump_len = 0;
 }
 
@@ -1173,8 +1172,8 @@ static int cpmac_probe(struct platform_device *pdev)
        snprintf(priv->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT,
                                                mdio_bus_id, phy_id);
 
-       priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link, 0,
-                                               PHY_INTERFACE_MODE_MII);
+       priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link,
+                               PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(priv->phy)) {
                if (netif_msg_drv(priv))
index 40aff684aa23af64fc3ff03f0c5a54df798c0484..b35e6a76664cec1882ad7c552c43524a3973f9c6 100644 (file)
@@ -374,6 +374,9 @@ void cpsw_tx_handler(void *token, int len, int status)
        struct net_device       *ndev = skb->dev;
        struct cpsw_priv        *priv = netdev_priv(ndev);
 
+       /* Check whether the queue is stopped due to stalled tx dma, if the
+        * queue is stopped then start the queue as we have free desc for tx
+        */
        if (unlikely(netif_queue_stopped(ndev)))
                netif_start_queue(ndev);
        cpts_tx_timestamp(&priv->cpts, skb);
@@ -592,7 +595,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
                           1 << slave_port, 0, ALE_MCAST_FWD_2);
 
        slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
-                                &cpsw_adjust_link, 0, slave->data->phy_if);
+                                &cpsw_adjust_link, slave->data->phy_if);
        if (IS_ERR(slave->phy)) {
                dev_err(priv->dev, "phy %s not found on slave %d\n",
                        slave->data->phy_id, slave->slave_num);
@@ -736,6 +739,12 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
                goto fail;
        }
 
+       /* If there is no more tx desc left free then we need to
+        * tell the kernel to stop sending us tx frames.
+        */
+       if (unlikely(cpdma_check_free_tx_desc(priv->txch)))
+               netif_stop_queue(ndev);
+
        return NETDEV_TX_OK;
 fail:
        priv->stats.tx_dropped++;
@@ -944,9 +953,10 @@ static void cpsw_get_drvinfo(struct net_device *ndev,
                             struct ethtool_drvinfo *info)
 {
        struct cpsw_priv *priv = netdev_priv(ndev);
-       strcpy(info->driver, "TI CPSW Driver v1.0");
-       strcpy(info->version, "1.0");
-       strcpy(info->bus_info, priv->pdev->name);
+
+       strlcpy(info->driver, "TI CPSW Driver v1.0", sizeof(info->driver));
+       strlcpy(info->version, "1.0", sizeof(info->version));
+       strlcpy(info->bus_info, priv->pdev->name, sizeof(info->bus_info));
 }
 
 static u32 cpsw_get_msglevel(struct net_device *ndev)
index 49956730cd8db884ac1696d108cb62fe61d49533..f8629186afbe7df4dacff3101be24582eb140cef 100644 (file)
@@ -105,13 +105,13 @@ struct cpdma_ctlr {
 };
 
 struct cpdma_chan {
+       struct cpdma_desc __iomem       *head, *tail;
+       void __iomem                    *hdp, *cp, *rxfree;
        enum cpdma_state                state;
        struct cpdma_ctlr               *ctlr;
        int                             chan_num;
        spinlock_t                      lock;
-       struct cpdma_desc __iomem       *head, *tail;
        int                             count;
-       void __iomem                    *hdp, *cp, *rxfree;
        u32                             mask;
        cpdma_handler_fn                handler;
        enum dma_data_direction         dir;
@@ -217,17 +217,27 @@ desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma)
 }
 
 static struct cpdma_desc __iomem *
-cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc)
+cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc, bool is_rx)
 {
        unsigned long flags;
        int index;
+       int desc_start;
+       int desc_end;
        struct cpdma_desc __iomem *desc = NULL;
 
        spin_lock_irqsave(&pool->lock, flags);
 
-       index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0,
-                                          num_desc, 0);
-       if (index < pool->num_desc) {
+       if (is_rx) {
+               desc_start = 0;
+               desc_end = pool->num_desc/2;
+        } else {
+               desc_start = pool->num_desc/2;
+               desc_end = pool->num_desc;
+       }
+
+       index = bitmap_find_next_zero_area(pool->bitmap,
+                               desc_end, desc_start, num_desc, 0);
+       if (index < desc_end) {
                bitmap_set(pool->bitmap, index, num_desc);
                desc = pool->iomap + pool->desc_size * index;
                pool->used_desc++;
@@ -668,7 +678,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
                goto unlock_ret;
        }
 
-       desc = cpdma_desc_alloc(ctlr->pool, 1);
+       desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan));
        if (!desc) {
                chan->stats.desc_alloc_fail++;
                ret = -ENOMEM;
@@ -704,6 +714,29 @@ unlock_ret:
 }
 EXPORT_SYMBOL_GPL(cpdma_chan_submit);
 
+bool cpdma_check_free_tx_desc(struct cpdma_chan *chan)
+{
+       unsigned long flags;
+       int index;
+       bool ret;
+       struct cpdma_ctlr       *ctlr = chan->ctlr;
+       struct cpdma_desc_pool  *pool = ctlr->pool;
+
+       spin_lock_irqsave(&pool->lock, flags);
+
+       index = bitmap_find_next_zero_area(pool->bitmap,
+                               pool->num_desc, pool->num_desc/2, 1, 0);
+
+       if (index < pool->num_desc)
+               ret = true;
+       else
+               ret = false;
+
+       spin_unlock_irqrestore(&pool->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc);
+
 static void __cpdma_chan_free(struct cpdma_chan *chan,
                              struct cpdma_desc __iomem *desc,
                              int outlen, int status)
index afa19a0c0d81000d265a8930c9ecec7220863518..8d2aeb2096ac9c3f34df4bf775fa24acd5814012 100644 (file)
@@ -88,6 +88,7 @@ int cpdma_chan_process(struct cpdma_chan *chan, int quota);
 int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
 void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr);
 int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable);
+bool cpdma_check_free_tx_desc(struct cpdma_chan *chan);
 
 enum cpdma_control {
        CPDMA_CMD_IDLE,                 /* write-only */
index 2a3e2c56bc60ef8a8d2a959086c13d75b8494f96..242ec55110d2c42b2885ff72118d751dd351f10f 100644 (file)
@@ -120,7 +120,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
 #define EMAC_DEF_TX_CH                 (0) /* Default 0th channel */
 #define EMAC_DEF_RX_CH                 (0) /* Default 0th channel */
 #define EMAC_DEF_RX_NUM_DESC           (128)
-#define EMAC_DEF_TX_NUM_DESC           (128)
 #define EMAC_DEF_MAX_TX_CH             (1) /* Max TX channels configured */
 #define EMAC_DEF_MAX_RX_CH             (1) /* Max RX channels configured */
 #define EMAC_POLL_WEIGHT               (64) /* Default NAPI poll weight */
@@ -342,7 +341,6 @@ struct emac_priv {
        u32 mac_hash2;
        u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
        u32 rx_addr_type;
-       atomic_t cur_tx;
        const char *phy_id;
 #ifdef CONFIG_OF
        struct device_node *phy_node;
@@ -480,8 +478,8 @@ static void emac_dump_regs(struct emac_priv *priv)
 static void emac_get_drvinfo(struct net_device *ndev,
                             struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, emac_version_string);
-       strcpy(info->version, EMAC_MODULE_VERSION);
+       strlcpy(info->driver, emac_version_string, sizeof(info->driver));
+       strlcpy(info->version, EMAC_MODULE_VERSION, sizeof(info->version));
 }
 
 /**
@@ -1050,10 +1048,10 @@ static void emac_tx_handler(void *token, int len, int status)
 {
        struct sk_buff          *skb = token;
        struct net_device       *ndev = skb->dev;
-       struct emac_priv        *priv = netdev_priv(ndev);
-
-       atomic_dec(&priv->cur_tx);
 
+       /* Check whether the queue is stopped due to stalled tx dma, if the
+        * queue is stopped then start the queue as we have free desc for tx
+        */
        if (unlikely(netif_queue_stopped(ndev)))
                netif_start_queue(ndev);
        ndev->stats.tx_packets++;
@@ -1101,7 +1099,10 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
                goto fail_tx;
        }
 
-       if (atomic_inc_return(&priv->cur_tx) >= EMAC_DEF_TX_NUM_DESC)
+       /* If there is no more tx desc left free then we need to
+        * tell the kernel to stop sending us tx frames.
+        */
+       if (unlikely(cpdma_check_free_tx_desc(priv->txchan)))
                netif_stop_queue(ndev);
 
        return NETDEV_TX_OK;
@@ -1264,7 +1265,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
        /* Store mac addr in priv and rx channel and set it in EMAC hw */
        memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
        memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len);
-       ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
        /* MAC address is configured only after the interface is enabled. */
        if (netif_running(ndev)) {
@@ -1600,7 +1600,7 @@ static int emac_dev_open(struct net_device *ndev)
 
        if (priv->phy_id && *priv->phy_id) {
                priv->phydev = phy_connect(ndev, priv->phy_id,
-                                          &emac_adjust_link, 0,
+                                          &emac_adjust_link,
                                           PHY_INTERFACE_MODE_MII);
 
                if (IS_ERR(priv->phydev)) {
index 96070e9b50dc26bae301e9f9918219dbe5812e69..36435499814b78d34020503caa41fdb00d2cd57f 100644 (file)
@@ -2195,7 +2195,6 @@ static int tile_net_set_mac_address(struct net_device *dev, void *p)
 
        /* ISSUE: Note that "dev_addr" is now a pointer. */
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
        return 0;
 }
index e321d0b6fc882a4969a1a45ef2ce4b7a5de29864..445c0595c997e4e75316bcaca11fd7c1b3dbd9ce 100644 (file)
@@ -1226,8 +1226,8 @@ int gelic_net_open(struct net_device *netdev)
 void gelic_net_get_drvinfo(struct net_device *netdev,
                           struct ethtool_drvinfo *info)
 {
-       strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
-       strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int gelic_ether_get_settings(struct net_device *netdev,
index 9c288cd7d1718f4c444117313b2d6ac051266065..ffe519382e111a04dd37c904a6080cee561e2d47 100644 (file)
@@ -72,11 +72,13 @@ spider_net_ethtool_get_drvinfo(struct net_device *netdev,
        card = netdev_priv(netdev);
 
        /* clear and fill out info */
-       memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
-       strncpy(drvinfo->driver, spider_net_driver_name, 32);
-       strncpy(drvinfo->version, VERSION, 32);
-       strcpy(drvinfo->fw_version, "no information");
-       strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
+       strlcpy(drvinfo->driver, spider_net_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "no information",
+               sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(card->pdev),
+               sizeof(drvinfo->bus_info));
 }
 
 static void
index 9819349eaa1e88a1a3cfe2ffd3958b9665ee5b20..fe256094db35d8c745873a29851e5622746b999a 100644 (file)
@@ -633,9 +633,8 @@ static int tc_mii_probe(struct net_device *dev)
 
        /* attach the mac to the phy */
        phydev = phy_connect(dev, dev_name(&phydev->dev),
-                            &tc_handle_link_change, 0,
-                            lp->chiptype == TC35815_TX4939 ?
-                            PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
+                            &tc_handle_link_change,
+                            lp->chiptype == TC35815_TX4939 ? PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
        if (IS_ERR(phydev)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
                return PTR_ERR(phydev);
@@ -856,7 +855,6 @@ static int tc35815_init_one(struct pci_dev *pdev,
        if (rc)
                goto err_out;
 
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
                dev->name,
                chip_info[ent->driver_data].name,
@@ -1976,9 +1974,10 @@ tc35815_set_multicast_list(struct net_device *dev)
 static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct tc35815_local *lp = netdev_priv(dev);
-       strcpy(info->driver, MODNAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(lp->pci_dev));
+
+       strlcpy(info->driver, MODNAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(lp->pci_dev), sizeof(info->bus_info));
 }
 
 static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 7992b3e05d3dd5a48f7701114a2264d23f3ce4e8..ec4a5e1c6fb2c5c791b89f03eddf106430f3b5b2 100644 (file)
@@ -417,6 +417,12 @@ enum chip_cmd_bits {
        Cmd1NoTxPoll=0x08, Cmd1Reset=0x80,
 };
 
+struct rhine_stats {
+       u64             packets;
+       u64             bytes;
+       struct u64_stats_sync syncp;
+};
+
 struct rhine_private {
        /* Bit mask for configured VLAN ids */
        unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -458,6 +464,8 @@ struct rhine_private {
        unsigned int cur_rx, dirty_rx;  /* Producer/consumer ring indices */
        unsigned int cur_tx, dirty_tx;
        unsigned int rx_buf_sz;         /* Based on MTU+slack. */
+       struct rhine_stats rx_stats;
+       struct rhine_stats tx_stats;
        u8 wolopts;
 
        u8 tx_thresh, rx_thresh;
@@ -495,7 +503,8 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance);
 static void rhine_tx(struct net_device *dev);
 static int rhine_rx(struct net_device *dev, int limit);
 static void rhine_set_rx_mode(struct net_device *dev);
-static struct net_device_stats *rhine_get_stats(struct net_device *dev);
+static struct rtnl_link_stats64 *rhine_get_stats64(struct net_device *dev,
+              struct rtnl_link_stats64 *stats);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static const struct ethtool_ops netdev_ethtool_ops;
 static int  rhine_close(struct net_device *dev);
@@ -842,7 +851,7 @@ static const struct net_device_ops rhine_netdev_ops = {
        .ndo_open                = rhine_open,
        .ndo_stop                = rhine_close,
        .ndo_start_xmit          = rhine_start_tx,
-       .ndo_get_stats           = rhine_get_stats,
+       .ndo_get_stats64         = rhine_get_stats64,
        .ndo_set_rx_mode         = rhine_set_rx_mode,
        .ndo_change_mtu          = eth_change_mtu,
        .ndo_validate_addr       = eth_validate_addr,
@@ -990,7 +999,6 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                netdev_info(dev, "Using random MAC address: %pM\n",
                            dev->dev_addr);
        }
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        /* For Rhine-I/II, phy_id is loaded from EEPROM */
        if (!phy_id)
@@ -1791,8 +1799,11 @@ static void rhine_tx(struct net_device *dev)
                                dev->stats.collisions += txstatus & 0x0F;
                        netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n",
                                  (txstatus >> 3) & 0xF, txstatus & 0xF);
-                       dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
-                       dev->stats.tx_packets++;
+
+                       u64_stats_update_begin(&rp->tx_stats.syncp);
+                       rp->tx_stats.bytes += rp->tx_skbuff[entry]->len;
+                       rp->tx_stats.packets++;
+                       u64_stats_update_end(&rp->tx_stats.syncp);
                }
                /* Free the original skb. */
                if (rp->tx_skbuff_dma[entry]) {
@@ -1924,8 +1935,11 @@ static int rhine_rx(struct net_device *dev, int limit)
                        if (unlikely(desc_length & DescTag))
                                __vlan_hwaccel_put_tag(skb, vlan_tci);
                        netif_receive_skb(skb);
-                       dev->stats.rx_bytes += pkt_len;
-                       dev->stats.rx_packets++;
+
+                       u64_stats_update_begin(&rp->rx_stats.syncp);
+                       rp->rx_stats.bytes += pkt_len;
+                       rp->rx_stats.packets++;
+                       u64_stats_update_end(&rp->rx_stats.syncp);
                }
                entry = (++rp->cur_rx) % RX_RING_SIZE;
                rp->rx_head_desc = &rp->rx_ring[entry];
@@ -2020,15 +2034,31 @@ out_unlock:
        mutex_unlock(&rp->task_lock);
 }
 
-static struct net_device_stats *rhine_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
        struct rhine_private *rp = netdev_priv(dev);
+       unsigned int start;
 
        spin_lock_bh(&rp->lock);
        rhine_update_rx_crc_and_missed_errord(rp);
        spin_unlock_bh(&rp->lock);
 
-       return &dev->stats;
+       netdev_stats_to_stats64(stats, &dev->stats);
+
+       do {
+               start = u64_stats_fetch_begin_bh(&rp->rx_stats.syncp);
+               stats->rx_packets = rp->rx_stats.packets;
+               stats->rx_bytes = rp->rx_stats.bytes;
+       } while (u64_stats_fetch_retry_bh(&rp->rx_stats.syncp, start));
+
+       do {
+               start = u64_stats_fetch_begin_bh(&rp->tx_stats.syncp);
+               stats->tx_packets = rp->tx_stats.packets;
+               stats->tx_bytes = rp->tx_stats.bytes;
+       } while (u64_stats_fetch_retry_bh(&rp->tx_stats.syncp, start));
+
+       return stats;
 }
 
 static void rhine_set_rx_mode(struct net_device *dev)
index 35238389032669576f0080a17d1dd56a4919737e..545043cc4c0b4c54feb26787940ed4951f33974f 100644 (file)
@@ -570,7 +570,6 @@ static int w5100_set_macaddr(struct net_device *ndev, void *addr)
        if (!is_valid_ether_addr(sock_addr->sa_data))
                return -EADDRNOTAVAIL;
        memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN);
-       ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
        w5100_write_macaddr(priv);
        return 0;
 }
index 9d1d986f8d409bf8cc87a43acbeb2270b3b8594a..7cbd0e6fc6f3b1e6fbe612efd7233df4557f4cdc 100644 (file)
@@ -490,7 +490,6 @@ static int w5300_set_macaddr(struct net_device *ndev, void *addr)
        if (!is_valid_ether_addr(sock_addr->sa_data))
                return -EADDRNOTAVAIL;
        memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN);
-       ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
        w5300_write_macaddr(priv);
        return 0;
 }
index aad909d793d75c2817a00ea580f7303e7ba37257..5022093286f043a3e918e6dac105c9bb36d8e115 100644 (file)
@@ -319,18 +319,10 @@ out:
  * net_device_ops
  */
 
-static int temac_set_mac_address(struct net_device *ndev, void *address)
+static void temac_do_set_mac_address(struct net_device *ndev)
 {
        struct temac_local *lp = netdev_priv(ndev);
 
-       if (address)
-               memcpy(ndev->dev_addr, address, ETH_ALEN);
-
-       if (!is_valid_ether_addr(ndev->dev_addr))
-               eth_hw_addr_random(ndev);
-       else
-               ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
-
        /* set up unicast MAC address filter set its mac address */
        mutex_lock(&lp->indirect_mutex);
        temac_indirect_out32(lp, XTE_UAW0_OFFSET,
@@ -344,15 +336,26 @@ static int temac_set_mac_address(struct net_device *ndev, void *address)
                             (ndev->dev_addr[4] & 0x000000ff) |
                             (ndev->dev_addr[5] << 8));
        mutex_unlock(&lp->indirect_mutex);
+}
 
+static int temac_init_mac_address(struct net_device *ndev, void *address)
+{
+       memcpy(ndev->dev_addr, address, ETH_ALEN);
+       if (!is_valid_ether_addr(ndev->dev_addr))
+               eth_hw_addr_random(ndev);
+       temac_do_set_mac_address(ndev);
        return 0;
 }
 
-static int netdev_set_mac_address(struct net_device *ndev, void *p)
+static int temac_set_mac_address(struct net_device *ndev, void *p)
 {
        struct sockaddr *addr = p;
 
-       return temac_set_mac_address(ndev, addr->sa_data);
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+       memcpy(ndev->dev_addr, addr->sa_data, ETH_ALEN);
+       temac_do_set_mac_address(ndev);
+       return 0;
 }
 
 static void temac_set_multicast_list(struct net_device *ndev)
@@ -579,7 +582,7 @@ static void temac_device_reset(struct net_device *ndev)
        temac_setoptions(ndev,
                         lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN));
 
-       temac_set_mac_address(ndev, NULL);
+       temac_do_set_mac_address(ndev);
 
        /* Set address filter table */
        temac_set_multicast_list(ndev);
@@ -938,7 +941,7 @@ static const struct net_device_ops temac_netdev_ops = {
        .ndo_open = temac_open,
        .ndo_stop = temac_stop,
        .ndo_start_xmit = temac_start_xmit,
-       .ndo_set_mac_address = netdev_set_mac_address,
+       .ndo_set_mac_address = temac_set_mac_address,
        .ndo_validate_addr = eth_validate_addr,
        .ndo_do_ioctl = temac_ioctl,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1106,7 +1109,7 @@ static int temac_of_probe(struct platform_device *op)
                rc = -ENODEV;
                goto err_iounmap_2;
        }
-       temac_set_mac_address(ndev, (void *)addr);
+       temac_init_mac_address(ndev, (void *)addr);
 
        rc = temac_mdio_setup(lp, op->dev.of_node);
        if (rc)
index 6f47100e58d71584ea13bb0c83c1607ca967a58a..278c9db3b5b853e4cb41caf83a6990db517a899d 100644 (file)
@@ -1124,9 +1124,8 @@ static int axienet_ethtools_set_settings(struct net_device *ndev,
 static void axienet_ethtools_get_drvinfo(struct net_device *ndev,
                                         struct ethtool_drvinfo *ed)
 {
-       memset(ed, 0, sizeof(struct ethtool_drvinfo));
-       strcpy(ed->driver, DRIVER_NAME);
-       strcpy(ed->version, DRIVER_VERSION);
+       strlcpy(ed->driver, DRIVER_NAME, sizeof(ed->driver));
+       strlcpy(ed->version, DRIVER_VERSION, sizeof(ed->version));
        ed->regdump_len = sizeof(u32) * AXIENET_REGS_N;
 }
 
index 94a1f94f74b89f7a4d9a05c47ea0a44672c1adc8..98e09d0d3ce22e153603efc37f486dfdf55174ac 100644 (file)
@@ -1412,7 +1412,8 @@ static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
        strlcpy(info->driver, "xirc2ps_cs", sizeof(info->driver));
-       sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+       snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx",
+                dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
index d3ebb73277bed4306363aaa20b9ea699d49bcc20..6958a5e87703bb3625b917bcdecfe8a7ef50e7e9 100644 (file)
@@ -977,11 +977,12 @@ static void ixp4xx_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
        struct port *port = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
+
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
        snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u",
                 port->firmware[0], port->firmware[1],
                 port->firmware[2], port->firmware[3]);
-       strcpy(info->bus_info, "internal");
+       strlcpy(info->bus_info, "internal", sizeof(info->bus_info));
 }
 
 static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1450,7 +1451,7 @@ static int eth_init_one(struct platform_device *pdev)
 
        snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
                mdio_bus->id, plat->phy);
-       port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
+       port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link,
                                   PHY_INTERFACE_MODE_MII);
        if (IS_ERR(port->phydev)) {
                err = PTR_ERR(port->phydev);
index 8264f0ef7692f5c832a12336a1188f9c7620190f..d5202a4b08774e99f9c4bd6c59e731ecb47f6b30 100644 (file)
@@ -304,9 +304,9 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 static void netvsc_get_drvinfo(struct net_device *net,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, KBUILD_MODNAME);
-       strcpy(info->version, HV_DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, HV_DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 }
 
 static int netvsc_change_mtu(struct net_device *ndev, int mtu)
index 1e9cb0bbf62cbcf0c4738388802560ab961f0657..8f1c25676d44f2aab087d85e06576d9037d3f87b 100644 (file)
@@ -372,7 +372,6 @@ static int ieee802154fake_probe(struct platform_device *pdev)
 
        memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
                        dev->addr_len);
-       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
        /*
         * For now we'd like to emulate 2.4 GHz-only device,
index 344dceb1aaf9e70d3c36540d1ea2b62524fba368..82164381f778fb604b07f5cc2956a16e76d3f563 100644 (file)
@@ -90,7 +90,7 @@ static void ri_tasklet(unsigned long dev)
                u64_stats_update_end(&dp->tsync);
 
                rcu_read_lock();
-               skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif);
+               skb->dev = dev_get_by_index_rcu(dev_net(_dev), skb->skb_iif);
                if (!skb->dev) {
                        rcu_read_unlock();
                        dev_kfree_skb(skb);
index d3fb97d97cbcb61f68deda7c3009a83393515656..7b44ebd7770e03b59d7da1ca49e7c7968a4991d6 100644 (file)
@@ -375,7 +375,6 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
 
        if (!(dev->flags & IFF_UP)) {
                /* Just copy in the new address */
-               dev->addr_assign_type &= ~NET_ADDR_RANDOM;
                memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
        } else {
                /* Rehash and update the device filters */
@@ -586,8 +585,8 @@ static int macvlan_fdb_del(struct ndmsg *ndm,
 static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *drvinfo)
 {
-       snprintf(drvinfo->driver, 32, "macvlan");
-       snprintf(drvinfo->version, 32, "0.1");
+       strlcpy(drvinfo->driver, "macvlan", sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, "0.1", sizeof(drvinfo->version));
 }
 
 static int macvlan_ethtool_get_settings(struct net_device *dev,
@@ -765,16 +764,22 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
                memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
        }
 
+       err = netdev_upper_dev_link(lowerdev, dev);
+       if (err)
+               goto destroy_port;
+
        port->count += 1;
        err = register_netdevice(dev);
        if (err < 0)
-               goto destroy_port;
+               goto upper_dev_unlink;
 
        list_add_tail(&vlan->list, &port->vlans);
        netif_stacked_transfer_operstate(lowerdev, dev);
 
        return 0;
 
+upper_dev_unlink:
+       netdev_upper_dev_unlink(lowerdev, dev);
 destroy_port:
        port->count -= 1;
        if (!port->count)
@@ -798,6 +803,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head)
 
        list_del(&vlan->list);
        unregister_netdevice_queue(dev, head);
+       netdev_upper_dev_unlink(vlan->lowerdev, dev);
 }
 EXPORT_SYMBOL_GPL(macvlan_dellink);
 
index 0f0f9ce3a7769ec552cc9f01f1915b44e44958fe..b181dfb3d6d600362235f7be38703a6827530f96 100644 (file)
@@ -543,6 +543,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
                skb->data_len += len;
                skb->len += len;
                skb->truesize += truesize;
+               skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG;
                atomic_add(truesize, &skb->sk->sk_wmem_alloc);
                while (len) {
                        int off = base & ~PAGE_MASK;
@@ -598,7 +599,7 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
 
        if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
                skb_shinfo(skb)->gso_size = vnet_hdr->gso_size;
-               skb_shinfo(skb)->gso_type = gso_type;
+               skb_shinfo(skb)->gso_type |= gso_type;
 
                /* Header must be checked, and gso_segs computed. */
                skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
index 6989ebe2bc7902c44e429dfefda4c432d3eb7131..37add21a3d7d630d2a989312deab132017eb5fcf 100644 (file)
@@ -269,12 +269,18 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
 
 static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+       if (nt->np.ipv6)
+               return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
+       else
+               return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 }
 
 static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+       if (nt->np.ipv6)
+               return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
+       else
+               return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 }
 
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -410,7 +416,22 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
                return -EINVAL;
        }
 
-       nt->np.local_ip = in_aton(buf);
+       if (strnchr(buf, count, ':')) {
+               const char *end;
+               if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
+                       if (*end && *end != '\n') {
+                               printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+                               return -EINVAL;
+                       }
+                       nt->np.ipv6 = true;
+               } else
+                       return -EINVAL;
+       } else {
+               if (!nt->np.ipv6) {
+                       nt->np.local_ip.ip = in_aton(buf);
+               } else
+                       return -EINVAL;
+       }
 
        return strnlen(buf, count);
 }
@@ -426,7 +447,22 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
                return -EINVAL;
        }
 
-       nt->np.remote_ip = in_aton(buf);
+       if (strnchr(buf, count, ':')) {
+               const char *end;
+               if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
+                       if (*end && *end != '\n') {
+                               printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+                               return -EINVAL;
+                       }
+                       nt->np.ipv6 = true;
+               } else
+                       return -EINVAL;
+       } else {
+               if (!nt->np.ipv6) {
+                       nt->np.remote_ip.ip = in_aton(buf);
+               } else
+                       return -EINVAL;
+       }
 
        return strnlen(buf, count);
 }
index b983596abcbb740bb6416646afe0f401dbf0eaa7..29934446436ac0e6dd7df8d80797a3b4351d77ac 100644 (file)
@@ -5,15 +5,20 @@
  *
  * Author: David J. Choi
  *
- * Copyright (c) 2010 Micrel, Inc.
+ * Copyright (c) 2010-2013 Micrel, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  *
- * Support : ksz9021 1000/100/10 phy from Micrel
- *             ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
+ * Support : Micrel Phys:
+ *             Giga phys: ksz9021, ksz9031
+ *             100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
+ *                        ksz8021, ksz8031, ksz8051,
+ *                        ksz8081, ksz8091,
+ *                        ksz8061,
+ *             Switch : ksz8873, ksz886x
  */
 
 #include <linux/kernel.h>
@@ -176,7 +181,7 @@ static struct phy_driver ksphy_driver[] = {
 }, {
        .phy_id         = PHY_ID_KSZ8021,
        .phy_id_mask    = 0x00ffffff,
-       .name           = "Micrel KSZ8021",
+       .name           = "Micrel KSZ8021 or KSZ8031",
        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
@@ -224,6 +229,30 @@ static struct phy_driver ksphy_driver[] = {
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = kszphy_config_intr,
        .driver         = { .owner = THIS_MODULE,},
+}, {
+       .phy_id         = PHY_ID_KSZ8081,
+       .name           = "Micrel KSZ8081 or KSZ8091",
+       .phy_id_mask    = 0x00fffff0,
+       .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+       .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .config_init    = kszphy_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = kszphy_ack_interrupt,
+       .config_intr    = kszphy_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+}, {
+       .phy_id         = PHY_ID_KSZ8061,
+       .name           = "Micrel KSZ8061",
+       .phy_id_mask    = 0x00fffff0,
+       .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+       .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .config_init    = kszphy_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = kszphy_ack_interrupt,
+       .config_intr    = kszphy_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = PHY_ID_KSZ9021,
        .phy_id_mask    = 0x000ffffe,
@@ -237,6 +266,19 @@ static struct phy_driver ksphy_driver[] = {
        .ack_interrupt  = kszphy_ack_interrupt,
        .config_intr    = ksz9021_config_intr,
        .driver         = { .owner = THIS_MODULE, },
+}, {
+       .phy_id         = PHY_ID_KSZ9031,
+       .phy_id_mask    = 0x00fffff0,
+       .name           = "Micrel KSZ9031 Gigabit PHY",
+       .features       = (PHY_GBIT_FEATURES | SUPPORTED_Pause
+                               | SUPPORTED_Asym_Pause),
+       .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .config_init    = kszphy_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = kszphy_ack_interrupt,
+       .config_intr    = ksz9021_config_intr,
+       .driver         = { .owner = THIS_MODULE, },
 }, {
        .phy_id         = PHY_ID_KSZ8873MLL,
        .phy_id_mask    = 0x00fffff0,
@@ -247,6 +289,16 @@ static struct phy_driver ksphy_driver[] = {
        .config_aneg    = ksz8873mll_config_aneg,
        .read_status    = ksz8873mll_read_status,
        .driver         = { .owner = THIS_MODULE, },
+}, {
+       .phy_id         = PHY_ID_KSZ886X,
+       .phy_id_mask    = 0x00fffff0,
+       .name           = "Micrel KSZ886X Switch",
+       .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+       .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .config_init    = kszphy_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .driver         = { .owner = THIS_MODULE, },
 } };
 
 static int __init ksphy_init(void)
@@ -270,12 +322,16 @@ MODULE_LICENSE("GPL");
 
 static struct mdio_device_id __maybe_unused micrel_tbl[] = {
        { PHY_ID_KSZ9021, 0x000ffffe },
+       { PHY_ID_KSZ9031, 0x00fffff0 },
        { PHY_ID_KSZ8001, 0x00ffffff },
        { PHY_ID_KS8737, 0x00fffff0 },
        { PHY_ID_KSZ8021, 0x00ffffff },
        { PHY_ID_KSZ8041, 0x00fffff0 },
        { PHY_ID_KSZ8051, 0x00fffff0 },
+       { PHY_ID_KSZ8061, 0x00fffff0 },
+       { PHY_ID_KSZ8081, 0x00fffff0 },
        { PHY_ID_KSZ8873MLL, 0x00fffff0 },
+       { PHY_ID_KSZ886X, 0x00fffff0 },
        { }
 };
 
index 8af46e88a1815de2e2f344a85c125ffcb5f12732..9930f999956172fa20ad5e5a34d3db5297fe9c12 100644 (file)
@@ -416,16 +416,15 @@ static void phy_prepare_link(struct phy_device *phydev,
  * @dev: the network device to connect
  * @phydev: the pointer to the phy device
  * @handler: callback function for state change notifications
- * @flags: PHY device's dev_flags
  * @interface: PHY device's interface
  */
 int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
-                      void (*handler)(struct net_device *), u32 flags,
+                      void (*handler)(struct net_device *),
                       phy_interface_t interface)
 {
        int rc;
 
-       rc = phy_attach_direct(dev, phydev, flags, interface);
+       rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
        if (rc)
                return rc;
 
@@ -443,7 +442,6 @@ EXPORT_SYMBOL(phy_connect_direct);
  * @dev: the network device to connect
  * @bus_id: the id string of the PHY device to connect
  * @handler: callback function for state change notifications
- * @flags: PHY device's dev_flags
  * @interface: PHY device's interface
  *
  * Description: Convenience function for connecting ethernet
@@ -455,7 +453,7 @@ EXPORT_SYMBOL(phy_connect_direct);
  *   the desired functionality.
  */
 struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
-               void (*handler)(struct net_device *), u32 flags,
+               void (*handler)(struct net_device *),
                phy_interface_t interface)
 {
        struct phy_device *phydev;
@@ -471,7 +469,7 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
        }
        phydev = to_phy_device(d);
 
-       rc = phy_connect_direct(dev, phydev, handler, flags, interface);
+       rc = phy_connect_direct(dev, phydev, handler, interface);
        if (rc)
                return ERR_PTR(rc);
 
@@ -576,14 +574,13 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
  * phy_attach - attach a network device to a particular PHY device
  * @dev: network device to attach
  * @bus_id: Bus ID of PHY device to attach
- * @flags: PHY device's dev_flags
  * @interface: PHY device's interface
  *
  * Description: Same as phy_attach_direct() except that a PHY bus_id
  *     string is passed instead of a pointer to a struct phy_device.
  */
 struct phy_device *phy_attach(struct net_device *dev,
-               const char *bus_id, u32 flags, phy_interface_t interface)
+               const char *bus_id, phy_interface_t interface)
 {
        struct bus_type *bus = &mdio_bus_type;
        struct phy_device *phydev;
@@ -599,7 +596,7 @@ struct phy_device *phy_attach(struct net_device *dev,
        }
        phydev = to_phy_device(d);
 
-       rc = phy_attach_direct(dev, phydev, flags, interface);
+       rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
        if (rc)
                return ERR_PTR(rc);
 
index 72f93470ea351315d146c670ab7322f0331d342b..8e7af8354342c9ce6440e3131aad536fbe385c87 100644 (file)
@@ -23,6 +23,8 @@
 #define RTL821x_INER_INIT      0x6400
 #define RTL821x_INSR           0x13
 
+#define        RTL8211E_INER_LINK_STAT 0x10
+
 MODULE_DESCRIPTION("Realtek PHY driver");
 MODULE_AUTHOR("Johnson Leung");
 MODULE_LICENSE("GPL");
@@ -36,7 +38,7 @@ static int rtl821x_ack_interrupt(struct phy_device *phydev)
        return (err < 0) ? err : 0;
 }
 
-static int rtl821x_config_intr(struct phy_device *phydev)
+static int rtl8211b_config_intr(struct phy_device *phydev)
 {
        int err;
 
@@ -49,28 +51,63 @@ static int rtl821x_config_intr(struct phy_device *phydev)
        return err;
 }
 
+static int rtl8211e_config_intr(struct phy_device *phydev)
+{
+       int err;
+
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, RTL821x_INER,
+                               RTL8211E_INER_LINK_STAT);
+       else
+               err = phy_write(phydev, RTL821x_INER, 0);
+
+       return err;
+}
+
 /* RTL8211B */
-static struct phy_driver rtl821x_driver = {
+static struct phy_driver rtl8211b_driver = {
        .phy_id         = 0x001cc912,
-       .name           = "RTL821x Gigabit Ethernet",
+       .name           = "RTL8211B Gigabit Ethernet",
        .phy_id_mask    = 0x001fffff,
        .features       = PHY_GBIT_FEATURES,
        .flags          = PHY_HAS_INTERRUPT,
        .config_aneg    = &genphy_config_aneg,
        .read_status    = &genphy_read_status,
        .ack_interrupt  = &rtl821x_ack_interrupt,
-       .config_intr    = &rtl821x_config_intr,
+       .config_intr    = &rtl8211b_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+/* RTL8211E */
+static struct phy_driver rtl8211e_driver = {
+       .phy_id         = 0x001cc915,
+       .name           = "RTL8211E Gigabit Ethernet",
+       .phy_id_mask    = 0x001fffff,
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_aneg    = &genphy_config_aneg,
+       .read_status    = &genphy_read_status,
+       .ack_interrupt  = &rtl821x_ack_interrupt,
+       .config_intr    = &rtl8211e_config_intr,
+       .suspend        = genphy_suspend,
+       .resume         = genphy_resume,
        .driver         = { .owner = THIS_MODULE,},
 };
 
 static int __init realtek_init(void)
 {
-       return phy_driver_register(&rtl821x_driver);
+       int ret;
+
+       ret = phy_driver_register(&rtl8211b_driver);
+       if (ret < 0)
+               return -ENODEV;
+       return phy_driver_register(&rtl8211e_driver);
 }
 
 static void __exit realtek_exit(void)
 {
-       phy_driver_unregister(&rtl821x_driver);
+       phy_driver_unregister(&rtl8211b_driver);
+       phy_driver_unregister(&rtl8211e_driver);
 }
 
 module_init(realtek_init);
@@ -78,6 +115,7 @@ module_exit(realtek_exit);
 
 static struct mdio_device_id __maybe_unused realtek_tbl[] = {
        { 0x001cc912, 0x001fffff },
+       { 0x001cc915, 0x001fffff },
        { }
 };
 
index d8b9b1e8ee0221479e35dd143f36cc7eb4030913..f433b594388e170b28b1aa57a92485625d897cb6 100644 (file)
@@ -410,10 +410,10 @@ static void rionet_get_drvinfo(struct net_device *ndev,
 {
        struct rionet_private *rnet = netdev_priv(ndev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "n/a");
-       strcpy(info->bus_info, rnet->mport->name);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "n/a", sizeof(info->fw_version));
+       strlcpy(info->bus_info, rnet->mport->name, sizeof(info->bus_info));
 }
 
 static u32 rionet_get_msglevel(struct net_device *ndev)
index ad86660fb8f92b092f06c9b41d03e416991f4636..70d5d6bdf583c3defdb6ca43080e69724cbcf289 100644 (file)
@@ -28,6 +28,7 @@
 #include <net/genetlink.h>
 #include <net/netlink.h>
 #include <net/sch_generic.h>
+#include <generated/utsrelease.h>
 #include <linux/if_team.h>
 
 #define DRV_NAME "team"
@@ -1054,10 +1055,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                }
        }
 
-       err = netdev_set_master(port_dev, dev);
+       err = netdev_master_upper_dev_link(port_dev, dev);
        if (err) {
-               netdev_err(dev, "Device %s failed to set master\n", portname);
-               goto err_set_master;
+               netdev_err(dev, "Device %s failed to set upper link\n",
+                          portname);
+               goto err_set_upper_link;
        }
 
        err = netdev_rx_handler_register(port_dev, team_handle_frame,
@@ -1090,9 +1092,9 @@ err_option_port_add:
        netdev_rx_handler_unregister(port_dev);
 
 err_handler_register:
-       netdev_set_master(port_dev, NULL);
+       netdev_upper_dev_unlink(port_dev, dev);
 
-err_set_master:
+err_set_upper_link:
        team_port_disable_netpoll(port);
 
 err_enable_netpoll:
@@ -1136,7 +1138,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
        team_port_disable(team, port);
        list_del_rcu(&port->list);
        netdev_rx_handler_unregister(port_dev);
-       netdev_set_master(port_dev, NULL);
+       netdev_upper_dev_unlink(port_dev, dev);
        team_port_disable_netpoll(port);
        vlan_vids_del_by_dev(port_dev, dev);
        dev_close(port_dev);
@@ -1399,13 +1401,11 @@ static void team_destructor(struct net_device *dev)
 
 static int team_open(struct net_device *dev)
 {
-       netif_carrier_on(dev);
        return 0;
 }
 
 static int team_close(struct net_device *dev)
 {
-       netif_carrier_off(dev);
        return 0;
 }
 
@@ -1501,7 +1501,6 @@ static int team_set_mac_address(struct net_device *dev, void *p)
        if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        rcu_read_lock();
        list_for_each_entry_rcu(port, &team->port_list, list)
                if (team->ops.port_change_dev_addr)
@@ -1707,6 +1706,15 @@ static netdev_features_t team_fix_features(struct net_device *dev,
        return features;
 }
 
+static int team_change_carrier(struct net_device *dev, bool new_carrier)
+{
+       if (new_carrier)
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
+       return 0;
+}
+
 static const struct net_device_ops team_netdev_ops = {
        .ndo_init               = team_init,
        .ndo_uninit             = team_uninit,
@@ -1729,8 +1737,24 @@ static const struct net_device_ops team_netdev_ops = {
        .ndo_add_slave          = team_add_slave,
        .ndo_del_slave          = team_del_slave,
        .ndo_fix_features       = team_fix_features,
+       .ndo_change_carrier     = team_change_carrier,
 };
 
+/***********************
+ * ethtool interface
+ ***********************/
+
+static void team_ethtool_get_drvinfo(struct net_device *dev,
+                                    struct ethtool_drvinfo *drvinfo)
+{
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
+}
+
+static const struct ethtool_ops team_ethtool_ops = {
+       .get_drvinfo            = team_ethtool_get_drvinfo,
+       .get_link               = ethtool_op_get_link,
+};
 
 /***********************
  * rt netlink interface
@@ -1746,7 +1770,6 @@ static void team_setup_by_port(struct net_device *dev,
        dev->mtu = port_dev->mtu;
        memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
        memcpy(dev->dev_addr, port_dev->dev_addr, port_dev->addr_len);
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 }
 
 static int team_dev_type_check_change(struct net_device *dev,
@@ -1780,6 +1803,7 @@ static void team_setup(struct net_device *dev)
        ether_setup(dev);
 
        dev->netdev_ops = &team_netdev_ops;
+       dev->ethtool_ops = &team_ethtool_ops;
        dev->destructor = team_destructor;
        dev->tx_queue_len = 0;
        dev->flags |= IFF_MULTICAST;
@@ -2533,21 +2557,43 @@ send_event:
 
 }
 
+static void __team_carrier_check(struct team *team)
+{
+       struct team_port *port;
+       bool team_linkup;
+
+       team_linkup = false;
+       list_for_each_entry(port, &team->port_list, list) {
+               if (port->linkup) {
+                       team_linkup = true;
+                       break;
+               }
+       }
+
+       if (team_linkup)
+               netif_carrier_on(team->dev);
+       else
+               netif_carrier_off(team->dev);
+}
+
 static void __team_port_change_check(struct team_port *port, bool linkup)
 {
        if (port->state.linkup != linkup)
                __team_port_change_send(port, linkup);
+       __team_carrier_check(port->team);
 }
 
 static void __team_port_change_port_added(struct team_port *port, bool linkup)
 {
        __team_port_change_send(port, linkup);
+       __team_carrier_check(port->team);
 }
 
 static void __team_port_change_port_removed(struct team_port *port)
 {
        port->removed = true;
        __team_port_change_send(port, false);
+       __team_carrier_check(port->team);
 }
 
 static void team_port_change_check(struct team_port *port, bool linkup)
index cc09b67c23bcd30402d73a93594f7aef9cb100da..8d208dd929634c373794c62f001ccbc766b1e241 100644 (file)
@@ -1009,6 +1009,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
                skb->data_len += len;
                skb->len += len;
                skb->truesize += truesize;
+               skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG;
                atomic_add(truesize, &skb->sk->sk_wmem_alloc);
                while (len) {
                        int off = base & ~PAGE_MASK;
@@ -1154,16 +1155,18 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        }
 
        if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+               unsigned short gso_type = 0;
+
                pr_debug("GSO!\n");
                switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
                case VIRTIO_NET_HDR_GSO_TCPV4:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+                       gso_type = SKB_GSO_TCPV4;
                        break;
                case VIRTIO_NET_HDR_GSO_TCPV6:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+                       gso_type = SKB_GSO_TCPV6;
                        break;
                case VIRTIO_NET_HDR_GSO_UDP:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+                       gso_type = SKB_GSO_UDP;
                        break;
                default:
                        tun->dev->stats.rx_frame_errors++;
@@ -1172,9 +1175,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                }
 
                if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN)
-                       skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
+                       gso_type |= SKB_GSO_TCP_ECN;
 
                skb_shinfo(skb)->gso_size = gso.gso_size;
+               skb_shinfo(skb)->gso_type |= gso_type;
                if (skb_shinfo(skb)->gso_size == 0) {
                        tun->dev->stats.rx_frame_errors++;
                        kfree_skb(skb);
index e889631161b80f96237a2894c5c4c6ba733699c6..346c032aa7955ba7ff09ca2a698cc1374e2ae630 100644 (file)
@@ -167,6 +167,20 @@ struct asix_data {
        u8 res;
 };
 
+struct asix_rx_fixup_info {
+       struct sk_buff *ax_skb;
+       u32 header;
+       u16 size;
+       bool split_head;
+};
+
+struct asix_common_private {
+       struct asix_rx_fixup_info rx_fixup_info;
+};
+
+/* ASIX specific flags */
+#define FLAG_EEPROM_MAC                (1UL << 0)  /* init device MAC from eeprom */
+
 int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
                  u16 size, void *data);
 
@@ -176,7 +190,9 @@ int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
 void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
                          u16 index, u16 size, void *data);
 
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+                          struct asix_rx_fixup_info *rx);
+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);
 
 struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                              gfp_t flags);
index 50d167330d384e76b8d3ebfe9cd15cd26dd45c87..f7f623a5390ee94ec44fbe6dd8a47f1ebfd6a332 100644 (file)
@@ -51,49 +51,89 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
                               value, index, data, size);
 }
 
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+                          struct asix_rx_fixup_info *rx)
 {
        int offset = 0;
 
-       while (offset + sizeof(u32) < skb->len) {
-               struct sk_buff *ax_skb;
-               u16 size;
-               u32 header = get_unaligned_le32(skb->data + offset);
-
-               offset += sizeof(u32);
-
-               /* get the packet length */
-               size = (u16) (header & 0x7ff);
-               if (size != ((~header >> 16) & 0x07ff)) {
-                       netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
-                       return 0;
+       while (offset + sizeof(u16) <= skb->len) {
+               u16 remaining = 0;
+               unsigned char *data;
+
+               if (!rx->size) {
+                       if ((skb->len - offset == sizeof(u16)) ||
+                           rx->split_head) {
+                               if(!rx->split_head) {
+                                       rx->header = get_unaligned_le16(
+                                                       skb->data + offset);
+                                       rx->split_head = true;
+                                       offset += sizeof(u16);
+                                       break;
+                               } else {
+                                       rx->header |= (get_unaligned_le16(
+                                                       skb->data + offset)
+                                                       << 16);
+                                       rx->split_head = false;
+                                       offset += sizeof(u16);
+                               }
+                       } else {
+                               rx->header = get_unaligned_le32(skb->data +
+                                                               offset);
+                               offset += sizeof(u32);
+                       }
+
+                       /* get the packet length */
+                       rx->size = (u16) (rx->header & 0x7ff);
+                       if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
+                               netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
+                                          rx->header, offset);
+                               rx->size = 0;
+                               return 0;
+                       }
+                       rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
+                                                              rx->size);
+                       if (!rx->ax_skb)
+                               return 0;
                }
 
-               if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
-                   (size + offset > skb->len)) {
+               if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
                        netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
-                                  size);
+                                  rx->size);
+                       kfree_skb(rx->ax_skb);
                        return 0;
                }
-               ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
-               if (!ax_skb)
-                       return 0;
 
-               skb_put(ax_skb, size);
-               memcpy(ax_skb->data, skb->data + offset, size);
-               usbnet_skb_return(dev, ax_skb);
+               if (rx->size > skb->len - offset) {
+                       remaining = rx->size - (skb->len - offset);
+                       rx->size = skb->len - offset;
+               }
+
+               data = skb_put(rx->ax_skb, rx->size);
+               memcpy(data, skb->data + offset, rx->size);
+               if (!remaining)
+                       usbnet_skb_return(dev, rx->ax_skb);
 
-               offset += (size + 1) & 0xfffe;
+               offset += (rx->size + 1) & 0xfffe;
+               rx->size = remaining;
        }
 
        if (skb->len != offset) {
-               netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
-                          skb->len);
+               netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
+                          skb->len, offset);
                return 0;
        }
+
        return 1;
 }
 
+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
+{
+       struct asix_common_private *dp = dev->driver_priv;
+       struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
+
+       return asix_rx_fixup_internal(dev, skb, rx);
+}
+
 struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                              gfp_t flags)
 {
@@ -510,8 +550,8 @@ void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
 {
        /* Inherit standard device info */
        usbnet_get_drvinfo(net, info);
-       strncpy (info->driver, DRIVER_NAME, sizeof info->driver);
-       strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+       strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
        info->eedump_len = AX_EEPROM_LEN;
 }
 
index 7a6e758f48e738e4652cc11ea39cd2d913d5f4b9..2205dbc8d32fc2bbcb74e5c82047913edc3fdd24 100644 (file)
@@ -422,14 +422,25 @@ static const struct net_device_ops ax88772_netdev_ops = {
 
 static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-       int ret, embd_phy;
+       int ret, embd_phy, i;
        u8 buf[ETH_ALEN];
        u32 phyid;
 
        usbnet_get_endpoints(dev,intf);
 
        /* Get the MAC address */
-       ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
+       if (dev->driver_info->data & FLAG_EEPROM_MAC) {
+               for (i = 0; i < (ETH_ALEN >> 1); i++) {
+                       ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i,
+                                       0, 2, buf + i * 2);
+                       if (ret < 0)
+                               break;
+               }
+       } else {
+               ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+                               0, 0, ETH_ALEN, buf);
+       }
+
        if (ret < 0) {
                netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
                return ret;
@@ -484,9 +495,19 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
                dev->rx_urb_size = 2048;
        }
 
+       dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
+       if (!dev->driver_priv)
+               return -ENOMEM;
+
        return 0;
 }
 
+static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+       if (dev->driver_priv)
+               kfree(dev->driver_priv);
+}
+
 static const struct ethtool_ops ax88178_ethtool_ops = {
        .get_drvinfo            = asix_get_drvinfo,
        .get_link               = asix_get_link,
@@ -818,6 +839,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
                dev->rx_urb_size = 2048;
        }
 
+       dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
+       if (!dev->driver_priv)
+                       return -ENOMEM;
+
        return 0;
 }
 
@@ -864,22 +889,38 @@ static const struct driver_info hawking_uf200_info = {
 static const struct driver_info ax88772_info = {
        .description = "ASIX AX88772 USB 2.0 Ethernet",
        .bind = ax88772_bind,
+       .unbind = ax88772_unbind,
        .status = asix_status,
        .link_reset = ax88772_link_reset,
        .reset = ax88772_reset,
        .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
-       .rx_fixup = asix_rx_fixup,
+       .rx_fixup = asix_rx_fixup_common,
        .tx_fixup = asix_tx_fixup,
 };
 
+static const struct driver_info ax88772b_info = {
+       .description = "ASIX AX88772B USB 2.0 Ethernet",
+       .bind = ax88772_bind,
+       .unbind = ax88772_unbind,
+       .status = asix_status,
+       .link_reset = ax88772_link_reset,
+       .reset = ax88772_reset,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+                FLAG_MULTI_PACKET,
+       .rx_fixup = asix_rx_fixup_common,
+       .tx_fixup = asix_tx_fixup,
+       .data = FLAG_EEPROM_MAC,
+};
+
 static const struct driver_info ax88178_info = {
        .description = "ASIX AX88178 USB 2.0 Ethernet",
        .bind = ax88178_bind,
+       .unbind = ax88772_unbind,
        .status = asix_status,
        .link_reset = ax88178_link_reset,
        .reset = ax88178_reset,
        .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
-       .rx_fixup = asix_rx_fixup,
+       .rx_fixup = asix_rx_fixup_common,
        .tx_fixup = asix_tx_fixup,
 };
 
@@ -953,7 +994,7 @@ static const struct usb_device_id   products [] = {
 }, {
        // ASIX AX88772B 10/100
        USB_DEVICE (0x0b95, 0x772b),
-       .driver_info = (unsigned long) &ax88772_info,
+       .driver_info = (unsigned long) &ax88772b_info,
 }, {
        // ASIX AX88772 10/100
        USB_DEVICE (0x0b95, 0x7720),
index c8e0aa85fb8e64ea5c610505a130d196ebe858ed..76ee5410d69e55074b6b9b34d93686add1a8910f 100644 (file)
@@ -35,6 +35,7 @@ struct ax88172a_private {
        u16 phy_addr;
        u16 oldmode;
        int use_embdphy;
+       struct asix_rx_fixup_info rx_fixup_info;
 };
 
 /* MDIO read and write wrappers for phylib */
@@ -377,7 +378,7 @@ static int ax88172a_reset(struct usbnet *dev)
 
        priv->phydev = phy_connect(dev->net, priv->phy_name,
                                   &ax88172a_adjust_link,
-                                  0, PHY_INTERFACE_MODE_MII);
+                                  PHY_INTERFACE_MODE_MII);
        if (IS_ERR(priv->phydev)) {
                netdev_err(dev->net, "Could not connect to PHY device %s\n",
                           priv->phy_name);
@@ -400,6 +401,14 @@ out:
 
 }
 
+static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       struct ax88172a_private *dp = dev->driver_priv;
+       struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
+
+       return asix_rx_fixup_internal(dev, skb, rx);
+}
+
 const struct driver_info ax88172a_info = {
        .description = "ASIX AX88172A USB 2.0 Ethernet",
        .bind = ax88172a_bind,
@@ -409,6 +418,6 @@ const struct driver_info ax88172a_info = {
        .status = ax88172a_status,
        .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
                 FLAG_MULTI_PACKET,
-       .rx_fixup = asix_rx_fixup,
+       .rx_fixup = ax88172a_rx_fixup,
        .tx_fixup = asix_tx_fixup,
 };
index 18d9579123ea82a2b649e0f2bdcdaa6a9f2ca80c..8d5cac2d8e33bee6b2545d45e83d24f52f8ac4c3 100644 (file)
@@ -685,9 +685,9 @@ static void catc_get_drvinfo(struct net_device *dev,
                             struct ethtool_drvinfo *info)
 {
        struct catc *catc = netdev_priv(dev);
-       strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-       usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info);
+       strlcpy(info->driver, driver_name, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+       usb_make_path(catc->usbdev, info->bus_info, sizeof(info->bus_info));
 }
 
 static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 9197b2c72ca36dd9e62bbccafbea388d5fc99793..b5ad7eadc4fa6e04644f79767510126c823db545 100644 (file)
@@ -65,9 +65,9 @@ cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
 {
        struct usbnet *dev = netdev_priv(net);
 
-       strncpy(info->driver, dev->driver_name, sizeof(info->driver));
-       strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
-       strncpy(info->fw_version, dev->driver_info->description,
+       strlcpy(info->driver, dev->driver_name, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, dev->driver_info->description,
                sizeof(info->fw_version));
        usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
 }
index d7e99445518eb5981d064a7378d7fcf02e4bf5cd..174e5ecea4cc9bb36dc880eb88096b122c0e63ef 100644 (file)
@@ -118,7 +118,7 @@ static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *valu
        dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
 
        for (i = 0; i < DM_TIMEOUT; i++) {
-               u8 tmp;
+               u8 tmp = 0;
 
                udelay(1);
                ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
@@ -161,7 +161,7 @@ static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 valu
        dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);
 
        for (i = 0; i < DM_TIMEOUT; i++) {
-               u8 tmp;
+               u8 tmp = 0;
 
                udelay(1);
                ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
index 92c49e0a59ec144a93abda0f04515185d9a5d0b0..0192073e53a30723927558e624789874511847b0 100644 (file)
@@ -159,7 +159,6 @@ kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
        }
 
        memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN);
-       memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN);
 
        return status;
 }
index a0b5807b30d4210816b7fe446ad241fe18da7ee8..8ee5ab0db12788523f52ee8d3137799c2547b1ac 100644 (file)
@@ -1074,8 +1074,9 @@ static void pegasus_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
 {
        pegasus_t *pegasus = netdev_priv(dev);
-       strncpy(info->driver, driver_name, sizeof(info->driver) - 1);
-       strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+
+       strlcpy(info->driver, driver_name, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
        usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info));
 }
 
@@ -1096,6 +1097,7 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        pegasus_t       *pegasus = netdev_priv(dev);
        u8              reg78 = 0x04;
+       int             ret;
 
        if (wol->wolopts & ~WOL_SUPPORTED)
                return -EINVAL;
@@ -1110,7 +1112,12 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        else
                pegasus->eth_regs[0] &= ~0x10;
        pegasus->wolopts = wol->wolopts;
-       return set_register(pegasus, WakeupControl, reg78);
+
+       ret = set_register(pegasus, WakeupControl, reg78);
+       if (!ret)
+               ret = device_set_wakeup_enable(&pegasus->usb->dev,
+                                               wol->wolopts);
+       return ret;
 }
 
 static inline void pegasus_reset_wol(struct net_device *dev)
index 4a4335833c36760548c67373ef71f17d05bba23c..cc49aac70224910f63fc6c5ed6b0b2fc720ff674 100644 (file)
@@ -431,7 +431,6 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
                goto halt_fail_and_release;
        }
        memcpy(net->dev_addr, bp, ETH_ALEN);
-       memcpy(net->perm_addr, bp, ETH_ALEN);
 
        /* set a nonzero filter to enable data transfers */
        memset(u.set, 0, sizeof *u.set);
index 5f39a3b225ef8729f47707dbfa2e8dcc98b52b54..a491d3a95393e4c533918c572ab7ba9256fa48ec 100644 (file)
@@ -776,9 +776,9 @@ static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinf
 {
        rtl8150_t *dev = netdev_priv(netdev);
 
-       strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-       usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);
+       strlcpy(info->driver, driver_name, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+       usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
 }
 
 static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
index 18dd4257ab17eaba7115ab33fe3bef2743f38a63..453aa6c1277c5347c2f5fa7864ba1c43f483a5a6 100644 (file)
@@ -598,8 +598,8 @@ static void sierra_net_get_drvinfo(struct net_device *net,
 {
        /* Inherit standard device info */
        usbnet_get_drvinfo(net, info);
-       strncpy(info->driver, driver_name, sizeof info->driver);
-       strncpy(info->version, DRIVER_VERSION, sizeof info->version);
+       strlcpy(info->driver, driver_name, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
 }
 
 static u32 sierra_net_get_link(struct net_device *net)
index 9b736701f854e33ae4b8ee4391f5f2135625da45..6a74a68220beee8a26554fc2c0ae70fe2c8becea 100644 (file)
 #define FEATURE_PHY_NLP_CROSSOVER      (0x02)
 #define FEATURE_AUTOSUSPEND            (0x04)
 
+#define SUSPEND_SUSPEND0               (0x01)
+#define SUSPEND_SUSPEND1               (0x02)
+#define SUSPEND_SUSPEND2               (0x04)
+#define SUSPEND_SUSPEND3               (0x08)
+#define SUSPEND_ALLMODES               (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
+                                        SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
+
 struct smsc95xx_priv {
        u32 mac_cr;
        u32 hash_hi;
@@ -62,6 +69,7 @@ struct smsc95xx_priv {
        u32 wolopts;
        spinlock_t mac_cr_lock;
        u8 features;
+       u8 suspend_flags;
 };
 
 static bool turbo_mode = true;
@@ -513,10 +521,8 @@ static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
        u32 flow, afc_cfg = 0;
 
        int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading AFC_CFG\n");
+       if (ret < 0)
                return ret;
-       }
 
        if (duplex == DUPLEX_FULL) {
                u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
@@ -541,16 +547,10 @@ static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
        }
 
        ret = smsc95xx_write_reg(dev, FLOW, flow);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing FLOW\n");
-               return ret;
-       }
-
-       ret = smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
        if (ret < 0)
-               netdev_warn(dev->net, "Error writing AFC_CFG\n");
+               return ret;
 
-       return ret;
+       return smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
 }
 
 static int smsc95xx_link_reset(struct usbnet *dev)
@@ -564,16 +564,12 @@ static int smsc95xx_link_reset(struct usbnet *dev)
 
        /* clear interrupt status */
        ret = smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing INT_STS\n");
+       if (ret < 0)
                return ret;
-       }
 
        mii_check_media(mii, 1, 1);
        mii_ethtool_gset(&dev->mii, &ecmd);
@@ -595,10 +591,8 @@ static int smsc95xx_link_reset(struct usbnet *dev)
        spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
 
        ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing MAC_CR\n");
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
        if (ret < 0)
@@ -638,10 +632,8 @@ static int smsc95xx_set_features(struct net_device *netdev,
        int ret;
 
        ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        if (features & NETIF_F_HW_CSUM)
                read_buf |= Tx_COE_EN_;
@@ -654,10 +646,8 @@ static int smsc95xx_set_features(struct net_device *netdev,
                read_buf &= ~Rx_COE_EN_;
 
        ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write COE_CR: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf);
        return 0;
@@ -800,16 +790,10 @@ static int smsc95xx_set_mac_address(struct usbnet *dev)
        int ret;
 
        ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret);
-               return ret;
-       }
-
-       ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
        if (ret < 0)
-               netdev_warn(dev->net, "Failed to write ADDRH: %d\n", ret);
+               return ret;
 
-       return ret;
+       return smsc95xx_write_reg(dev, ADDRH, addr_hi);
 }
 
 /* starts the TX path */
@@ -825,17 +809,11 @@ static int smsc95xx_start_tx_path(struct usbnet *dev)
        spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
 
        ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        /* Enable Tx at SCSRs */
-       ret = smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
-       if (ret < 0)
-               netdev_warn(dev->net, "Failed to write TX_CFG: %d\n", ret);
-
-       return ret;
+       return smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
 }
 
 /* Starts the Receive path */
@@ -843,17 +821,12 @@ static int smsc95xx_start_rx_path(struct usbnet *dev, int in_pm)
 {
        struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
        unsigned long flags;
-       int ret;
 
        spin_lock_irqsave(&pdata->mac_cr_lock, flags);
        pdata->mac_cr |= MAC_CR_RXEN_;
        spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
 
-       ret = __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
-       if (ret < 0)
-               netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
-
-       return ret;
+       return __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
 }
 
 static int smsc95xx_phy_initialize(struct usbnet *dev)
@@ -910,19 +883,15 @@ static int smsc95xx_reset(struct usbnet *dev)
        netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n");
 
        ret = smsc95xx_write_reg(dev, HW_CFG, HW_CFG_LRST_);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG\n");
+       if (ret < 0)
                return ret;
-       }
 
        timeout = 0;
        do {
                msleep(10);
                ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+               if (ret < 0)
                        return ret;
-               }
                timeout++;
        } while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
 
@@ -932,19 +901,15 @@ static int smsc95xx_reset(struct usbnet *dev)
        }
 
        ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        timeout = 0;
        do {
                msleep(10);
                ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret);
+               if (ret < 0)
                        return ret;
-               }
                timeout++;
        } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
 
@@ -961,10 +926,8 @@ static int smsc95xx_reset(struct usbnet *dev)
                  dev->net->dev_addr);
 
        ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n",
                  read_buf);
@@ -972,16 +935,12 @@ static int smsc95xx_reset(struct usbnet *dev)
        read_buf |= HW_CFG_BIR_;
 
        ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write HW_CFG_BIR_ bit in HW_CFG\n");
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        netif_dbg(dev, ifup, dev->net,
                  "Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n",
@@ -1002,42 +961,32 @@ static int smsc95xx_reset(struct usbnet *dev)
                  (ulong)dev->rx_urb_size);
 
        ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        netif_dbg(dev, ifup, dev->net,
                  "Read Value from BURST_CAP after writing: 0x%08x\n",
                  read_buf);
 
        ret = smsc95xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write BULK_IN_DLY: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        netif_dbg(dev, ifup, dev->net,
                  "Read Value from BULK_IN_DLY after writing: 0x%08x\n",
                  read_buf);
 
        ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG: 0x%08x\n",
                  read_buf);
@@ -1051,69 +1000,51 @@ static int smsc95xx_reset(struct usbnet *dev)
        read_buf |= NET_IP_ALIGN << 9;
 
        ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        netif_dbg(dev, ifup, dev->net,
                  "Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
 
        ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write INT_STS: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
        netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf);
 
        /* Configure GPIO pins as LED outputs */
        write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
                LED_GPIO_CFG_FDX_LED;
        ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write LED_GPIO_CFG: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        /* Init Tx */
        ret = smsc95xx_write_reg(dev, FLOW, 0);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        /* Don't need mac_cr_lock during initialisation */
        ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        /* Init Rx */
        /* Set Vlan */
        ret = smsc95xx_write_reg(dev, VLAN1, (u32)ETH_P_8021Q);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write VLAN1: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        /* Enable or disable checksum offload engines */
        ret = smsc95xx_set_features(dev->net, dev->net->features);
@@ -1131,19 +1062,15 @@ static int smsc95xx_reset(struct usbnet *dev)
        }
 
        ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        /* enable PHY interrupts */
        read_buf |= INT_EP_CTL_PHY_INT_;
 
        ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_start_tx_path(dev);
        if (ret < 0) {
@@ -1213,10 +1140,8 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
 
        /* detect device revision as different features may be available */
        ret = smsc95xx_read_reg(dev, ID_REV, &val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+       if (ret < 0)
                return ret;
-       }
        val >>= 16;
 
        if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9530_) ||
@@ -1261,17 +1186,13 @@ static int smsc95xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
 
        /* read to clear */
        ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+       if (ret < 0)
                return ret;
-       }
 
        /* enable interrupt source */
        ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PHY_INT_MASK\n");
+       if (ret < 0)
                return ret;
-       }
 
        ret |= mask;
 
@@ -1287,16 +1208,12 @@ static int smsc95xx_link_ok_nopm(struct usbnet *dev)
 
        /* first, a dummy read, needed to latch some MII phys */
        ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading MII_BMSR\n");
+       if (ret < 0)
                return ret;
-       }
 
        ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading MII_BMSR\n");
+       if (ret < 0)
                return ret;
-       }
 
        return !!(ret & BMSR_LSTATUS);
 }
@@ -1308,19 +1225,15 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
        int ret;
 
        ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PM_CTRL\n");
+       if (ret < 0)
                return ret;
-       }
 
        val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
        val |= PM_CTL_SUS_MODE_0;
 
        ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing PM_CTRL\n");
+       if (ret < 0)
                return ret;
-       }
 
        /* clear wol status */
        val &= ~PM_CTL_WUPS_;
@@ -1331,15 +1244,13 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
                val |= PM_CTL_WUPS_ED_;
 
        ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing PM_CTRL\n");
+       if (ret < 0)
                return ret;
-       }
 
        /* read back PM_CTRL */
        ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-       if (ret < 0)
-               netdev_warn(dev->net, "Error reading PM_CTRL\n");
+
+       pdata->suspend_flags |= SUSPEND_SUSPEND0;
 
        return ret;
 }
@@ -1360,10 +1271,8 @@ static int smsc95xx_enter_suspend1(struct usbnet *dev)
 
        /* enable energy detect power-down mode */
        ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_MODE_CTRL_STS);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PHY_MODE_CTRL_STS\n");
+       if (ret < 0)
                return ret;
-       }
 
        ret |= MODE_CTRL_STS_EDPWRDOWN_;
 
@@ -1371,52 +1280,133 @@ static int smsc95xx_enter_suspend1(struct usbnet *dev)
 
        /* enter SUSPEND1 mode */
        ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PM_CTRL\n");
+       if (ret < 0)
                return ret;
-       }
 
        val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
        val |= PM_CTL_SUS_MODE_1;
 
        ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing PM_CTRL\n");
+       if (ret < 0)
                return ret;
-       }
 
        /* clear wol status, enable energy detection */
        val &= ~PM_CTL_WUPS_;
        val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_);
 
        ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-       if (ret < 0)
-               netdev_warn(dev->net, "Error writing PM_CTRL\n");
+
+       pdata->suspend_flags |= SUSPEND_SUSPEND1;
 
        return ret;
 }
 
 static int smsc95xx_enter_suspend2(struct usbnet *dev)
 {
+       struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
        u32 val;
        int ret;
 
        ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PM_CTRL\n");
+       if (ret < 0)
                return ret;
-       }
 
        val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
        val |= PM_CTL_SUS_MODE_2;
 
        ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-       if (ret < 0)
-               netdev_warn(dev->net, "Error writing PM_CTRL\n");
+
+       pdata->suspend_flags |= SUSPEND_SUSPEND2;
 
        return ret;
 }
 
+static int smsc95xx_enter_suspend3(struct usbnet *dev)
+{
+       struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+       u32 val;
+       int ret;
+
+       ret = smsc95xx_read_reg_nopm(dev, RX_FIFO_INF, &val);
+       if (ret < 0)
+               return ret;
+
+       if (val & 0xFFFF) {
+               netdev_info(dev->net, "rx fifo not empty in autosuspend\n");
+               return -EBUSY;
+       }
+
+       ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+       if (ret < 0)
+               return ret;
+
+       val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
+       val |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS;
+
+       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       if (ret < 0)
+               return ret;
+
+       /* clear wol status */
+       val &= ~PM_CTL_WUPS_;
+       val |= PM_CTL_WUPS_WOL_;
+
+       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       if (ret < 0)
+               return ret;
+
+       pdata->suspend_flags |= SUSPEND_SUSPEND3;
+
+       return 0;
+}
+
+static int smsc95xx_autosuspend(struct usbnet *dev, u32 link_up)
+{
+       struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+       int ret;
+
+       if (!netif_running(dev->net)) {
+               /* interface is ifconfig down so fully power down hw */
+               netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n");
+               return smsc95xx_enter_suspend2(dev);
+       }
+
+       if (!link_up) {
+               /* link is down so enter EDPD mode, but only if device can
+                * reliably resume from it.  This check should be redundant
+                * as current FEATURE_AUTOSUSPEND parts also support
+                * FEATURE_PHY_NLP_CROSSOVER but it's included for clarity */
+               if (!(pdata->features & FEATURE_PHY_NLP_CROSSOVER)) {
+                       netdev_warn(dev->net, "EDPD not supported\n");
+                       return -EBUSY;
+               }
+
+               netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n");
+
+               /* enable PHY wakeup events for if cable is attached */
+               ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
+                       PHY_INT_MASK_ANEG_COMP_);
+               if (ret < 0) {
+                       netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+                       return ret;
+               }
+
+               netdev_info(dev->net, "entering SUSPEND1 mode\n");
+               return smsc95xx_enter_suspend1(dev);
+       }
+
+       /* enable PHY wakeup events so we remote wakeup if cable is pulled */
+       ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
+               PHY_INT_MASK_LINK_DOWN_);
+       if (ret < 0) {
+               netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+               return ret;
+       }
+
+       netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
+       return smsc95xx_enter_suspend3(dev);
+}
+
 static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct usbnet *dev = usb_get_intfdata(intf);
@@ -1424,15 +1414,35 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
        u32 val, link_up;
        int ret;
 
+       /* TODO: don't indicate this feature to usb framework if
+        * our current hardware doesn't have the capability
+        */
+       if ((message.event == PM_EVENT_AUTO_SUSPEND) &&
+           (!(pdata->features & FEATURE_AUTOSUSPEND))) {
+               netdev_warn(dev->net, "autosuspend not supported\n");
+               return -EBUSY;
+       }
+
        ret = usbnet_suspend(intf, message);
        if (ret < 0) {
                netdev_warn(dev->net, "usbnet_suspend error\n");
                return ret;
        }
 
+       if (pdata->suspend_flags) {
+               netdev_warn(dev->net, "error during last resume\n");
+               pdata->suspend_flags = 0;
+       }
+
        /* determine if link is up using only _nopm functions */
        link_up = smsc95xx_link_ok_nopm(dev);
 
+       if (message.event == PM_EVENT_AUTO_SUSPEND) {
+               ret = smsc95xx_autosuspend(dev, link_up);
+               goto done;
+       }
+
+       /* if we get this far we're not autosuspending */
        /* if no wol options set, or if link is down and we're not waking on
         * PHY activity, enter lowest power SUSPEND2 mode
         */
@@ -1442,32 +1452,24 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
 
                /* disable energy detect (link up) & wake up events */
                ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error reading WUCSR\n");
+               if (ret < 0)
                        goto done;
-               }
 
                val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);
 
                ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error writing WUCSR\n");
+               if (ret < 0)
                        goto done;
-               }
 
                ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error reading PM_CTRL\n");
+               if (ret < 0)
                        goto done;
-               }
 
                val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
 
                ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error writing PM_CTRL\n");
+               if (ret < 0)
                        goto done;
-               }
 
                ret = smsc95xx_enter_suspend2(dev);
                goto done;
@@ -1565,7 +1567,6 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                for (i = 0; i < (wuff_filter_count * 4); i++) {
                        ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]);
                        if (ret < 0) {
-                               netdev_warn(dev->net, "Error writing WUFF\n");
                                kfree(filter_mask);
                                goto done;
                        }
@@ -1574,67 +1575,51 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
 
                for (i = 0; i < (wuff_filter_count / 4); i++) {
                        ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]);
-                       if (ret < 0) {
-                               netdev_warn(dev->net, "Error writing WUFF\n");
+                       if (ret < 0)
                                goto done;
-                       }
                }
 
                for (i = 0; i < (wuff_filter_count / 4); i++) {
                        ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]);
-                       if (ret < 0) {
-                               netdev_warn(dev->net, "Error writing WUFF\n");
+                       if (ret < 0)
                                goto done;
-                       }
                }
 
                for (i = 0; i < (wuff_filter_count / 2); i++) {
                        ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]);
-                       if (ret < 0) {
-                               netdev_warn(dev->net, "Error writing WUFF\n");
+                       if (ret < 0)
                                goto done;
-                       }
                }
 
                /* clear any pending pattern match packet status */
                ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error reading WUCSR\n");
+               if (ret < 0)
                        goto done;
-               }
 
                val |= WUCSR_WUFR_;
 
                ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error writing WUCSR\n");
+               if (ret < 0)
                        goto done;
-               }
        }
 
        if (pdata->wolopts & WAKE_MAGIC) {
                /* clear any pending magic packet status */
                ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error reading WUCSR\n");
+               if (ret < 0)
                        goto done;
-               }
 
                val |= WUCSR_MPR_;
 
                ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error writing WUCSR\n");
+               if (ret < 0)
                        goto done;
-               }
        }
 
        /* enable/disable wakeup sources */
        ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading WUCSR\n");
+       if (ret < 0)
                goto done;
-       }
 
        if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
                netdev_info(dev->net, "enabling pattern match wakeup\n");
@@ -1653,17 +1638,13 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
        }
 
        ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing WUCSR\n");
+       if (ret < 0)
                goto done;
-       }
 
        /* enable wol wakeup source */
        ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error reading PM_CTRL\n");
+       if (ret < 0)
                goto done;
-       }
 
        val |= PM_CTL_WOL_EN_;
 
@@ -1672,10 +1653,8 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                val |= PM_CTL_ED_EN_;
 
        ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-       if (ret < 0) {
-               netdev_warn(dev->net, "Error writing PM_CTRL\n");
+       if (ret < 0)
                goto done;
-       }
 
        /* enable receiver to enable frame reception */
        smsc95xx_start_rx_path(dev, 1);
@@ -1694,42 +1673,40 @@ static int smsc95xx_resume(struct usb_interface *intf)
 {
        struct usbnet *dev = usb_get_intfdata(intf);
        struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+       u8 suspend_flags = pdata->suspend_flags;
        int ret;
        u32 val;
 
        BUG_ON(!dev);
 
-       if (pdata->wolopts) {
+       netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
+
+       /* do this first to ensure it's cleared even in error case */
+       pdata->suspend_flags = 0;
+
+       if (suspend_flags & SUSPEND_ALLMODES) {
                /* clear wake-up sources */
                ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error reading WUCSR\n");
+               if (ret < 0)
                        return ret;
-               }
 
                val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);
 
                ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error writing WUCSR\n");
+               if (ret < 0)
                        return ret;
-               }
 
                /* clear wake-up status */
                ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error reading PM_CTRL\n");
+               if (ret < 0)
                        return ret;
-               }
 
                val &= ~PM_CTL_WOL_EN_;
                val |= PM_CTL_WUPS_;
 
                ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-               if (ret < 0) {
-                       netdev_warn(dev->net, "Error writing PM_CTRL\n");
+               if (ret < 0)
                        return ret;
-               }
        }
 
        ret = usbnet_resume(intf);
@@ -1891,6 +1868,26 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
        return skb;
 }
 
+static int smsc95xx_manage_power(struct usbnet *dev, int on)
+{
+       struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+       dev->intf->needs_remote_wakeup = on;
+
+       if (pdata->features & FEATURE_AUTOSUSPEND)
+               return 0;
+
+       /* this chip revision doesn't support autosuspend */
+       netdev_info(dev->net, "hardware doesn't support USB autosuspend\n");
+
+       if (on)
+               usb_autopm_get_interface_no_resume(dev->intf);
+       else
+               usb_autopm_put_interface(dev->intf);
+
+       return 0;
+}
+
 static const struct driver_info smsc95xx_info = {
        .description    = "smsc95xx USB 2.0 Ethernet",
        .bind           = smsc95xx_bind,
@@ -1900,6 +1897,7 @@ static const struct driver_info smsc95xx_info = {
        .rx_fixup       = smsc95xx_rx_fixup,
        .tx_fixup       = smsc95xx_tx_fixup,
        .status         = smsc95xx_status,
+       .manage_power   = smsc95xx_manage_power,
        .flags          = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR,
 };
 
@@ -2007,6 +2005,7 @@ static struct usb_driver smsc95xx_driver = {
        .reset_resume   = smsc95xx_resume,
        .disconnect     = usbnet_disconnect,
        .disable_hub_initiated_lpm = 1,
+       .supports_autosuspend = 1,
 };
 
 module_usb_driver(smsc95xx_driver);
index 95814d9747ef1988657ccd72bc01d56501bc7b37..e1da42aaf9de94891e6bff691b129c2e362334fd 100644 (file)
 #define MIN_MTU 68             /* Min L3 MTU */
 #define MAX_MTU 65535          /* Max L3 MTU (arbitrary) */
 
-struct veth_net_stats {
-       u64                     rx_packets;
-       u64                     rx_bytes;
-       u64                     tx_packets;
-       u64                     tx_bytes;
-       u64                     rx_dropped;
+struct pcpu_vstats {
+       u64                     packets;
+       u64                     bytes;
        struct u64_stats_sync   syncp;
 };
 
 struct veth_priv {
-       struct net_device *peer;
-       struct veth_net_stats __percpu *stats;
+       struct net_device __rcu *peer;
+       atomic64_t              dropped;
 };
 
 /*
@@ -92,10 +89,10 @@ static int veth_get_sset_count(struct net_device *dev, int sset)
 static void veth_get_ethtool_stats(struct net_device *dev,
                struct ethtool_stats *stats, u64 *data)
 {
-       struct veth_priv *priv;
+       struct veth_priv *priv = netdev_priv(dev);
+       struct net_device *peer = rtnl_dereference(priv->peer);
 
-       priv = netdev_priv(dev);
-       data[0] = priv->peer->ifindex;
+       data[0] = peer ? peer->ifindex : 0;
 }
 
 static const struct ethtool_ops veth_ethtool_ops = {
@@ -107,50 +104,37 @@ static const struct ethtool_ops veth_ethtool_ops = {
        .get_ethtool_stats      = veth_get_ethtool_stats,
 };
 
-/*
- * xmit
- */
-
 static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct net_device *rcv = NULL;
-       struct veth_priv *priv, *rcv_priv;
-       struct veth_net_stats *stats, *rcv_stats;
-       int length;
-
-       priv = netdev_priv(dev);
-       rcv = priv->peer;
-       rcv_priv = netdev_priv(rcv);
-
-       stats = this_cpu_ptr(priv->stats);
-       rcv_stats = this_cpu_ptr(rcv_priv->stats);
-
+       struct veth_priv *priv = netdev_priv(dev);
+       struct net_device *rcv;
+       int length = skb->len;
+
+       rcu_read_lock();
+       rcv = rcu_dereference(priv->peer);
+       if (unlikely(!rcv)) {
+               kfree_skb(skb);
+               goto drop;
+       }
        /* don't change ip_summed == CHECKSUM_PARTIAL, as that
-          will cause bad checksum on forwarded packets */
+        * will cause bad checksum on forwarded packets
+        */
        if (skb->ip_summed == CHECKSUM_NONE &&
            rcv->features & NETIF_F_RXCSUM)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-       length = skb->len;
-       if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS)
-               goto rx_drop;
+       if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
+               struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
 
-       u64_stats_update_begin(&stats->syncp);
-       stats->tx_bytes += length;
-       stats->tx_packets++;
-       u64_stats_update_end(&stats->syncp);
-
-       u64_stats_update_begin(&rcv_stats->syncp);
-       rcv_stats->rx_bytes += length;
-       rcv_stats->rx_packets++;
-       u64_stats_update_end(&rcv_stats->syncp);
-
-       return NETDEV_TX_OK;
-
-rx_drop:
-       u64_stats_update_begin(&rcv_stats->syncp);
-       rcv_stats->rx_dropped++;
-       u64_stats_update_end(&rcv_stats->syncp);
+               u64_stats_update_begin(&stats->syncp);
+               stats->bytes += length;
+               stats->packets++;
+               u64_stats_update_end(&stats->syncp);
+       } else {
+drop:
+               atomic64_inc(&priv->dropped);
+       }
+       rcu_read_unlock();
        return NETDEV_TX_OK;
 }
 
@@ -158,47 +142,63 @@ rx_drop:
  * general routines
  */
 
-static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev,
-                                                 struct rtnl_link_stats64 *tot)
+static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
 {
        struct veth_priv *priv = netdev_priv(dev);
        int cpu;
 
+       result->packets = 0;
+       result->bytes = 0;
        for_each_possible_cpu(cpu) {
-               struct veth_net_stats *stats = per_cpu_ptr(priv->stats, cpu);
-               u64 rx_packets, rx_bytes, rx_dropped;
-               u64 tx_packets, tx_bytes;
+               struct pcpu_vstats *stats = per_cpu_ptr(dev->vstats, cpu);
+               u64 packets, bytes;
                unsigned int start;
 
                do {
                        start = u64_stats_fetch_begin_bh(&stats->syncp);
-                       rx_packets = stats->rx_packets;
-                       tx_packets = stats->tx_packets;
-                       rx_bytes = stats->rx_bytes;
-                       tx_bytes = stats->tx_bytes;
-                       rx_dropped = stats->rx_dropped;
+                       packets = stats->packets;
+                       bytes = stats->bytes;
                } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
-               tot->rx_packets += rx_packets;
-               tot->tx_packets += tx_packets;
-               tot->rx_bytes   += rx_bytes;
-               tot->tx_bytes   += tx_bytes;
-               tot->rx_dropped += rx_dropped;
+               result->packets += packets;
+               result->bytes += bytes;
        }
+       return atomic64_read(&priv->dropped);
+}
+
+static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev,
+                                                 struct rtnl_link_stats64 *tot)
+{
+       struct veth_priv *priv = netdev_priv(dev);
+       struct net_device *peer;
+       struct pcpu_vstats one;
+
+       tot->tx_dropped = veth_stats_one(&one, dev);
+       tot->tx_bytes = one.bytes;
+       tot->tx_packets = one.packets;
+
+       rcu_read_lock();
+       peer = rcu_dereference(priv->peer);
+       if (peer) {
+               tot->rx_dropped = veth_stats_one(&one, peer);
+               tot->rx_bytes = one.bytes;
+               tot->rx_packets = one.packets;
+       }
+       rcu_read_unlock();
 
        return tot;
 }
 
 static int veth_open(struct net_device *dev)
 {
-       struct veth_priv *priv;
+       struct veth_priv *priv = netdev_priv(dev);
+       struct net_device *peer = rtnl_dereference(priv->peer);
 
-       priv = netdev_priv(dev);
-       if (priv->peer == NULL)
+       if (!peer)
                return -ENOTCONN;
 
-       if (priv->peer->flags & IFF_UP) {
+       if (peer->flags & IFF_UP) {
                netif_carrier_on(dev);
-               netif_carrier_on(priv->peer);
+               netif_carrier_on(peer);
        }
        return 0;
 }
@@ -206,9 +206,11 @@ static int veth_open(struct net_device *dev)
 static int veth_close(struct net_device *dev)
 {
        struct veth_priv *priv = netdev_priv(dev);
+       struct net_device *peer = rtnl_dereference(priv->peer);
 
        netif_carrier_off(dev);
-       netif_carrier_off(priv->peer);
+       if (peer)
+               netif_carrier_off(peer);
 
        return 0;
 }
@@ -228,24 +230,16 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
 
 static int veth_dev_init(struct net_device *dev)
 {
-       struct veth_net_stats __percpu *stats;
-       struct veth_priv *priv;
-
-       stats = alloc_percpu(struct veth_net_stats);
-       if (stats == NULL)
+       dev->vstats = alloc_percpu(struct pcpu_vstats);
+       if (!dev->vstats)
                return -ENOMEM;
 
-       priv = netdev_priv(dev);
-       priv->stats = stats;
        return 0;
 }
 
 static void veth_dev_free(struct net_device *dev)
 {
-       struct veth_priv *priv;
-
-       priv = netdev_priv(dev);
-       free_percpu(priv->stats);
+       free_percpu(dev->vstats);
        free_netdev(dev);
 }
 
@@ -259,6 +253,10 @@ static const struct net_device_ops veth_netdev_ops = {
        .ndo_set_mac_address = eth_mac_addr,
 };
 
+#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO |    \
+                      NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | \
+                      NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)
+
 static void veth_setup(struct net_device *dev)
 {
        ether_setup(dev);
@@ -269,9 +267,10 @@ static void veth_setup(struct net_device *dev)
        dev->netdev_ops = &veth_netdev_ops;
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
+       dev->features |= VETH_FEATURES;
        dev->destructor = veth_dev_free;
 
-       dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
+       dev->hw_features = VETH_FEATURES;
 }
 
 /*
@@ -396,10 +395,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
         */
 
        priv = netdev_priv(dev);
-       priv->peer = peer;
+       rcu_assign_pointer(priv->peer, peer);
 
        priv = netdev_priv(peer);
-       priv->peer = dev;
+       rcu_assign_pointer(priv->peer, dev);
        return 0;
 
 err_register_dev:
@@ -420,7 +419,16 @@ static void veth_dellink(struct net_device *dev, struct list_head *head)
        struct net_device *peer;
 
        priv = netdev_priv(dev);
-       peer = priv->peer;
+       peer = rtnl_dereference(priv->peer);
+
+       /* Note : dellink() is called from default_device_exit_batch(),
+        * before a rcu_synchronize() point. The devices are guaranteed
+        * not being freed before one RCU grace period.
+        */
+       RCU_INIT_POINTER(priv->peer, NULL);
+
+       priv = netdev_priv(peer);
+       RCU_INIT_POINTER(priv->peer, NULL);
 
        unregister_netdevice_queue(dev, head);
        unregister_netdevice_queue(peer, head);
index 35c00c5ea02adcbdf6f2855b7ee506544944843a..eda2042a6466bfa9fa6696753e9a3c3691d1d0ff 100644 (file)
@@ -227,6 +227,7 @@ static void set_skb_frag(struct sk_buff *skb, struct page *page,
        skb->len += size;
        skb->truesize += PAGE_SIZE;
        skb_shinfo(skb)->nr_frags++;
+       skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG;
        *len -= size;
 }
 
@@ -386,16 +387,18 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
                 ntohs(skb->protocol), skb->len, skb->pkt_type);
 
        if (hdr->hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+               unsigned short gso_type = 0;
+
                pr_debug("GSO!\n");
                switch (hdr->hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
                case VIRTIO_NET_HDR_GSO_TCPV4:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+                       gso_type = SKB_GSO_TCPV4;
                        break;
                case VIRTIO_NET_HDR_GSO_UDP:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+                       gso_type = SKB_GSO_UDP;
                        break;
                case VIRTIO_NET_HDR_GSO_TCPV6:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+                       gso_type = SKB_GSO_TCPV6;
                        break;
                default:
                        net_warn_ratelimited("%s: bad gso type %u.\n",
@@ -404,7 +407,7 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
                }
 
                if (hdr->hdr.gso_type & VIRTIO_NET_HDR_GSO_ECN)
-                       skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
+                       gso_type |= SKB_GSO_TCP_ECN;
 
                skb_shinfo(skb)->gso_size = hdr->hdr.gso_size;
                if (skb_shinfo(skb)->gso_size == 0) {
@@ -412,6 +415,7 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
                        goto frame_err;
                }
 
+               skb_shinfo(skb)->gso_type |= gso_type;
                /* Header must be checked, and gso_segs computed. */
                skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
                skb_shinfo(skb)->gso_segs = 0;
@@ -760,19 +764,77 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 }
 
+/*
+ * Send command via the control virtqueue and check status.  Commands
+ * supported by the hypervisor, as indicated by feature bits, should
+ * never fail unless improperly formated.
+ */
+static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
+                                struct scatterlist *data, int out, int in)
+{
+       struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
+       struct virtio_net_ctrl_hdr ctrl;
+       virtio_net_ctrl_ack status = ~0;
+       unsigned int tmp;
+       int i;
+
+       /* Caller should know better */
+       BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ||
+               (out + in > VIRTNET_SEND_COMMAND_SG_MAX));
+
+       out++; /* Add header */
+       in++; /* Add return status */
+
+       ctrl.class = class;
+       ctrl.cmd = cmd;
+
+       sg_init_table(sg, out + in);
+
+       sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
+       for_each_sg(data, s, out + in - 2, i)
+               sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
+       sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
+
+       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
+
+       virtqueue_kick(vi->cvq);
+
+       /* Spin for a response, the kick causes an ioport write, trapping
+        * into the hypervisor, so the request should be handled immediately.
+        */
+       while (!virtqueue_get_buf(vi->cvq, &tmp))
+               cpu_relax();
+
+       return status == VIRTIO_NET_OK;
+}
+
 static int virtnet_set_mac_address(struct net_device *dev, void *p)
 {
        struct virtnet_info *vi = netdev_priv(dev);
        struct virtio_device *vdev = vi->vdev;
        int ret;
+       struct sockaddr *addr = p;
+       struct scatterlist sg;
 
-       ret = eth_mac_addr(dev, p);
+       ret = eth_prepare_mac_addr_change(dev, p);
        if (ret)
                return ret;
 
-       if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC))
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
+               sg_init_one(&sg, addr->sa_data, dev->addr_len);
+               if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
+                                         VIRTIO_NET_CTRL_MAC_ADDR_SET,
+                                         &sg, 1, 0)) {
+                       dev_warn(&vdev->dev,
+                                "Failed to set mac address by vq command.\n");
+                       return -EINVAL;
+               }
+       } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
                vdev->config->set(vdev, offsetof(struct virtio_net_config, mac),
-                                 dev->dev_addr, dev->addr_len);
+                                 addr->sa_data, dev->addr_len);
+       }
+
+       eth_commit_mac_addr_change(dev, p);
 
        return 0;
 }
@@ -826,51 +888,6 @@ static void virtnet_netpoll(struct net_device *dev)
 }
 #endif
 
-/*
- * Send command via the control virtqueue and check status.  Commands
- * supported by the hypervisor, as indicated by feature bits, should
- * never fail unless improperly formated.
- */
-static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
-                                struct scatterlist *data, int out, int in)
-{
-       struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
-       struct virtio_net_ctrl_hdr ctrl;
-       virtio_net_ctrl_ack status = ~0;
-       unsigned int tmp;
-       int i;
-
-       /* Caller should know better */
-       BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ||
-               (out + in > VIRTNET_SEND_COMMAND_SG_MAX));
-
-       out++; /* Add header */
-       in++; /* Add return status */
-
-       ctrl.class = class;
-       ctrl.cmd = cmd;
-
-       sg_init_table(sg, out + in);
-
-       sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
-       for_each_sg(data, s, out + in - 2, i)
-               sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
-       sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
-
-       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
-
-       virtqueue_kick(vi->cvq);
-
-       /*
-        * Spin for a response, the kick causes an ioport write, trapping
-        * into the hypervisor, so the request should be handled immediately.
-        */
-       while (!virtqueue_get_buf(vi->cvq, &tmp))
-               cpu_relax();
-
-       return status == VIRTIO_NET_OK;
-}
-
 static void virtnet_ack_link_announce(struct virtnet_info *vi)
 {
        rtnl_lock();
@@ -1706,6 +1723,7 @@ static unsigned int features[] = {
        VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
        VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
        VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
+       VIRTIO_NET_F_CTRL_MAC_ADDR,
 };
 
 static struct virtio_driver virtio_net_driver = {
index dc8913c6238c965b0905ef7ad6784bf669f06388..b1c90f8ccd3d39a4dfb806c428cd8e665d2f0a82 100644 (file)
@@ -43,11 +43,7 @@ static DEFINE_PCI_DEVICE_TABLE(vmxnet3_pciid_table) = {
 
 MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
 
-static atomic_t devices_found;
-
-#define VMXNET3_MAX_DEVICES 10
 static int enable_mq = 1;
-static int irq_share_mode;
 
 static void
 vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac);
@@ -152,8 +148,8 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
 
        adapter->link_speed = ret >> 16;
        if (ret & 1) { /* Link is up. */
-               printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n",
-                      adapter->netdev->name, adapter->link_speed);
+               netdev_info(adapter->netdev, "NIC Link is Up %d Mbps\n",
+                           adapter->link_speed);
                if (!netif_carrier_ok(adapter->netdev))
                        netif_carrier_on(adapter->netdev);
 
@@ -163,8 +159,7 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
                                                 adapter);
                }
        } else {
-               printk(KERN_INFO "%s: NIC Link is Down\n",
-                      adapter->netdev->name);
+               netdev_info(adapter->netdev, "NIC Link is Down\n");
                if (netif_carrier_ok(adapter->netdev))
                        netif_carrier_off(adapter->netdev);
 
@@ -510,8 +505,7 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
                           * sizeof(struct Vmxnet3_TxDesc),
                           &tq->tx_ring.basePA);
        if (!tq->tx_ring.base) {
-               printk(KERN_ERR "%s: failed to allocate tx ring\n",
-                      adapter->netdev->name);
+               netdev_err(adapter->netdev, "failed to allocate tx ring\n");
                goto err;
        }
 
@@ -520,8 +514,7 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
                             sizeof(struct Vmxnet3_TxDataDesc),
                             &tq->data_ring.basePA);
        if (!tq->data_ring.base) {
-               printk(KERN_ERR "%s: failed to allocate data ring\n",
-                      adapter->netdev->name);
+               netdev_err(adapter->netdev, "failed to allocate data ring\n");
                goto err;
        }
 
@@ -530,8 +523,7 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
                             sizeof(struct Vmxnet3_TxCompDesc),
                             &tq->comp_ring.basePA);
        if (!tq->comp_ring.base) {
-               printk(KERN_ERR "%s: failed to allocate tx comp ring\n",
-                      adapter->netdev->name);
+               netdev_err(adapter->netdev, "failed to allocate tx comp ring\n");
                goto err;
        }
 
@@ -580,15 +572,14 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
 
                if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
                        if (rbi->skb == NULL) {
-                               rbi->skb = dev_alloc_skb(rbi->len +
-                                                        NET_IP_ALIGN);
+                               rbi->skb = __netdev_alloc_skb_ip_align(adapter->netdev,
+                                                                      rbi->len,
+                                                                      GFP_KERNEL);
                                if (unlikely(rbi->skb == NULL)) {
                                        rq->stats.rx_buf_alloc_failure++;
                                        break;
                                }
-                               rbi->skb->dev = adapter->netdev;
 
-                               skb_reserve(rbi->skb, NET_IP_ALIGN);
                                rbi->dma_addr = pci_map_single(adapter->pdev,
                                                rbi->skb->data, rbi->len,
                                                PCI_DMA_FROMDEVICE);
@@ -629,12 +620,10 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
                num_allocated++;
                vmxnet3_cmd_ring_adv_next2fill(ring);
        }
-       rq->uncommitted[ring_idx] += num_allocated;
 
-       dev_dbg(&adapter->netdev->dev,
-               "alloc_rx_buf: %d allocated, next2fill %u, next2comp "
-               "%u, uncommitted %u\n", num_allocated, ring->next2fill,
-               ring->next2comp, rq->uncommitted[ring_idx]);
+       netdev_dbg(adapter->netdev,
+               "alloc_rx_buf: %d allocated, next2fill %u, next2comp %u\n",
+               num_allocated, ring->next2fill, ring->next2comp);
 
        /* so that the device can distinguish a full ring and an empty ring */
        BUG_ON(num_allocated != 0 && ring->next2fill == ring->next2comp);
@@ -691,7 +680,7 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
                tbi = tq->buf_info + tq->tx_ring.next2fill;
                tbi->map_type = VMXNET3_MAP_NONE;
 
-               dev_dbg(&adapter->netdev->dev,
+               netdev_dbg(adapter->netdev,
                        "txd[%u]: 0x%Lx 0x%x 0x%x\n",
                        tq->tx_ring.next2fill,
                        le64_to_cpu(ctx->sop_txd->txd.addr),
@@ -731,7 +720,7 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
                gdesc->dword[2] = cpu_to_le32(dw2);
                gdesc->dword[3] = 0;
 
-               dev_dbg(&adapter->netdev->dev,
+               netdev_dbg(adapter->netdev,
                        "txd[%u]: 0x%Lx 0x%x 0x%x\n",
                        tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
                        le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
@@ -771,7 +760,7 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
                        gdesc->dword[2] = cpu_to_le32(dw2);
                        gdesc->dword[3] = 0;
 
-                       dev_dbg(&adapter->netdev->dev,
+                       netdev_dbg(adapter->netdev,
                                "txd[%u]: 0x%llu %u %u\n",
                                tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
                                le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
@@ -871,7 +860,7 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
        tdd = tq->data_ring.base + tq->tx_ring.next2fill;
 
        memcpy(tdd->data, skb->data, ctx->copy_size);
-       dev_dbg(&adapter->netdev->dev,
+       netdev_dbg(adapter->netdev,
                "copy %u bytes to dataRing[%u]\n",
                ctx->copy_size, tq->tx_ring.next2fill);
        return 1;
@@ -977,7 +966,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
 
        if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
                tq->stats.tx_ring_full++;
-               dev_dbg(&adapter->netdev->dev,
+               netdev_dbg(adapter->netdev,
                        "tx queue stopped on %s, next2comp %u"
                        " next2fill %u\n", adapter->netdev->name,
                        tq->tx_ring.next2comp, tq->tx_ring.next2fill);
@@ -1060,7 +1049,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                           (struct Vmxnet3_TxDesc *)ctx.sop_txd);
        gdesc = ctx.sop_txd;
 #endif
-       dev_dbg(&adapter->netdev->dev,
+       netdev_dbg(adapter->netdev,
                "txd[%u]: SOP 0x%Lx 0x%x 0x%x\n",
                (u32)(ctx.sop_txd -
                tq->tx_ring.base), le64_to_cpu(gdesc->txd.addr),
@@ -1213,7 +1202,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                        if (unlikely(rcd->len == 0)) {
                                /* Pretend the rx buffer is skipped. */
                                BUG_ON(!(rcd->sop && rcd->eop));
-                               dev_dbg(&adapter->netdev->dev,
+                               netdev_dbg(adapter->netdev,
                                        "rxRing[%u][%u] 0 length\n",
                                        ring_idx, idx);
                                goto rcd_done;
@@ -1221,7 +1210,8 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
 
                        skip_page_frags = false;
                        ctx->skb = rbi->skb;
-                       new_skb = dev_alloc_skb(rbi->len + NET_IP_ALIGN);
+                       new_skb = netdev_alloc_skb_ip_align(adapter->netdev,
+                                                           rbi->len);
                        if (new_skb == NULL) {
                                /* Skb allocation failed, do not handover this
                                 * skb to stack. Reuse it. Drop the existing pkt
@@ -1236,11 +1226,14 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                        pci_unmap_single(adapter->pdev, rbi->dma_addr, rbi->len,
                                         PCI_DMA_FROMDEVICE);
 
+#ifdef VMXNET3_RSS
+                       if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE &&
+                           (adapter->netdev->features & NETIF_F_RXHASH))
+                               ctx->skb->rxhash = le32_to_cpu(rcd->rssHash);
+#endif
                        skb_put(ctx->skb, rcd->len);
 
                        /* Immediate refill */
-                       new_skb->dev = adapter->netdev;
-                       skb_reserve(new_skb, NET_IP_ALIGN);
                        rbi->skb = new_skb;
                        rbi->dma_addr = pci_map_single(adapter->pdev,
                                                       rbi->skb->data, rbi->len,
@@ -1333,7 +1326,6 @@ rcd_done:
                        VMXNET3_WRITE_BAR0_REG(adapter,
                                               rxprod_reg[ring_idx] + rq->qid * 8,
                                               ring->next2fill);
-                       rq->uncommitted[ring_idx] = 0;
                }
 
                vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
@@ -1378,7 +1370,6 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
                rq->rx_ring[ring_idx].gen = VMXNET3_INIT_GEN;
                rq->rx_ring[ring_idx].next2fill =
                                        rq->rx_ring[ring_idx].next2comp = 0;
-               rq->uncommitted[ring_idx] = 0;
        }
 
        rq->comp_ring.gen = VMXNET3_INIT_GEN;
@@ -1459,7 +1450,6 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
        /* reset internal state and allocate buffers for both rings */
        for (i = 0; i < 2; i++) {
                rq->rx_ring[i].next2fill = rq->rx_ring[i].next2comp = 0;
-               rq->uncommitted[i] = 0;
 
                memset(rq->rx_ring[i].base, 0, rq->rx_ring[i].size *
                       sizeof(struct Vmxnet3_RxDesc));
@@ -1518,8 +1508,8 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
                rq->rx_ring[i].base = pci_alloc_consistent(adapter->pdev, sz,
                                                        &rq->rx_ring[i].basePA);
                if (!rq->rx_ring[i].base) {
-                       printk(KERN_ERR "%s: failed to allocate rx ring %d\n",
-                              adapter->netdev->name, i);
+                       netdev_err(adapter->netdev,
+                                  "failed to allocate rx ring %d\n", i);
                        goto err;
                }
        }
@@ -1528,8 +1518,7 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
        rq->comp_ring.base = pci_alloc_consistent(adapter->pdev, sz,
                                                  &rq->comp_ring.basePA);
        if (!rq->comp_ring.base) {
-               printk(KERN_ERR "%s: failed to allocate rx comp ring\n",
-                      adapter->netdev->name);
+               netdev_err(adapter->netdev, "failed to allocate rx comp ring\n");
                goto err;
        }
 
@@ -1821,9 +1810,10 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
                                          adapter->rx_queue[i].name,
                                          &(adapter->rx_queue[i]));
                        if (err) {
-                               printk(KERN_ERR "Failed to request irq for MSIX"
-                                      ", %s, error %d\n",
-                                      adapter->rx_queue[i].name, err);
+                               netdev_err(adapter->netdev,
+                                          "Failed to request irq for MSIX, "
+                                          "%s, error %d\n",
+                                          adapter->rx_queue[i].name, err);
                                return err;
                        }
 
@@ -1852,8 +1842,9 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
 #endif
        intr->num_intrs = vector + 1;
        if (err) {
-               printk(KERN_ERR "Failed to request irq %s (intr type:%d), error"
-                      ":%d\n", adapter->netdev->name, intr->type, err);
+               netdev_err(adapter->netdev,
+                          "Failed to request irq (intr type:%d), error %d\n",
+                          intr->type, err);
        } else {
                /* Number of rx queues will not change after this */
                for (i = 0; i < adapter->num_rx_queues; i++) {
@@ -1874,9 +1865,9 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
                        adapter->rx_queue[0].comp_ring.intr_idx = 0;
                }
 
-               printk(KERN_INFO "%s: intr type %u, mode %u, %u vectors "
-                      "allocated\n", adapter->netdev->name, intr->type,
-                      intr->mask_mode, intr->num_intrs);
+               netdev_info(adapter->netdev,
+                           "intr type %u, mode %u, %u vectors allocated\n",
+                           intr->type, intr->mask_mode, intr->num_intrs);
        }
 
        return err;
@@ -2042,8 +2033,8 @@ vmxnet3_set_mc(struct net_device *netdev)
                                rxConf->mfTablePA = cpu_to_le64(virt_to_phys(
                                                    new_table));
                        } else {
-                               printk(KERN_INFO "%s: failed to copy mcast list"
-                                      ", setting ALL_MULTI\n", netdev->name);
+                               netdev_info(netdev, "failed to copy mcast list"
+                                           ", setting ALL_MULTI\n");
                                new_mode |= VMXNET3_RXM_ALL_MULTI;
                        }
                }
@@ -2171,6 +2162,14 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
 
        if (adapter->rss) {
                struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+               static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
+                       0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
+                       0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
+                       0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
+                       0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
+                       0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
+               };
+
                devRead->misc.uptFeatures |= UPT1_F_RSS;
                devRead->misc.numRxQueues = adapter->num_rx_queues;
                rssConf->hashType = UPT1_RSS_HASH_TYPE_TCP_IPV4 |
@@ -2180,7 +2179,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
                rssConf->hashFunc = UPT1_RSS_HASH_FUNC_TOEPLITZ;
                rssConf->hashKeySize = UPT1_RSS_MAX_KEY_SIZE;
                rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
-               get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize);
+               memcpy(rssConf->hashKey, rss_key, sizeof(rss_key));
+
                for (i = 0; i < rssConf->indTableSize; i++)
                        rssConf->indTable[i] = ethtool_rxfh_indir_default(
                                i, adapter->num_rx_queues);
@@ -2218,7 +2218,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
        u32 ret;
        unsigned long flags;
 
-       dev_dbg(&adapter->netdev->dev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
+       netdev_dbg(adapter->netdev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
                " ring sizes %u %u %u\n", adapter->netdev->name,
                adapter->skb_buf_size, adapter->rx_buf_per_pkt,
                adapter->tx_queue[0].tx_ring.size,
@@ -2228,15 +2228,15 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
        vmxnet3_tq_init_all(adapter);
        err = vmxnet3_rq_init_all(adapter);
        if (err) {
-               printk(KERN_ERR "Failed to init rx queue for %s: error %d\n",
-                      adapter->netdev->name, err);
+               netdev_err(adapter->netdev,
+                          "Failed to init rx queue error %d\n", err);
                goto rq_err;
        }
 
        err = vmxnet3_request_irqs(adapter);
        if (err) {
-               printk(KERN_ERR "Failed to setup irq for %s: error %d\n",
-                      adapter->netdev->name, err);
+               netdev_err(adapter->netdev,
+                          "Failed to setup irq for error %d\n", err);
                goto irq_err;
        }
 
@@ -2253,8 +2253,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
        spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
        if (ret != 0) {
-               printk(KERN_ERR "Failed to activate dev %s: error %u\n",
-                      adapter->netdev->name, ret);
+               netdev_err(adapter->netdev,
+                          "Failed to activate dev: error %u\n", ret);
                err = -EINVAL;
                goto activate_err;
        }
@@ -2369,23 +2369,22 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
 
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR "Failed to enable adapter %s: error %d\n",
-                      pci_name(pdev), err);
+               dev_err(&pdev->dev, "Failed to enable adapter: error %d\n", err);
                return err;
        }
 
        if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
                if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
-                       printk(KERN_ERR "pci_set_consistent_dma_mask failed "
-                              "for adapter %s\n", pci_name(pdev));
+                       dev_err(&pdev->dev,
+                               "pci_set_consistent_dma_mask failed\n");
                        err = -EIO;
                        goto err_set_mask;
                }
                *dma64 = true;
        } else {
                if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
-                       printk(KERN_ERR "pci_set_dma_mask failed for adapter "
-                              "%s\n",  pci_name(pdev));
+                       dev_err(&pdev->dev,
+                               "pci_set_dma_mask failed\n");
                        err = -EIO;
                        goto err_set_mask;
                }
@@ -2395,8 +2394,8 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
        err = pci_request_selected_regions(pdev, (1 << 2) - 1,
                                           vmxnet3_driver_name);
        if (err) {
-               printk(KERN_ERR "Failed to request region for adapter %s: "
-                      "error %d\n", pci_name(pdev), err);
+               dev_err(&pdev->dev,
+                       "Failed to request region for adapter: error %d\n", err);
                goto err_set_mask;
        }
 
@@ -2406,8 +2405,7 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
        mmio_len = pci_resource_len(pdev, 0);
        adapter->hw_addr0 = ioremap(mmio_start, mmio_len);
        if (!adapter->hw_addr0) {
-               printk(KERN_ERR "Failed to map bar0 for adapter %s\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Failed to map bar0\n");
                err = -EIO;
                goto err_ioremap;
        }
@@ -2416,8 +2414,7 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
        mmio_len = pci_resource_len(pdev, 1);
        adapter->hw_addr1 = ioremap(mmio_start, mmio_len);
        if (!adapter->hw_addr1) {
-               printk(KERN_ERR "Failed to map bar1 for adapter %s\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Failed to map bar1\n");
                err = -EIO;
                goto err_bar1;
        }
@@ -2524,12 +2521,14 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size,
                err = vmxnet3_rq_create(rq, adapter);
                if (err) {
                        if (i == 0) {
-                               printk(KERN_ERR "Could not allocate any rx"
-                                      "queues. Aborting.\n");
+                               netdev_err(adapter->netdev,
+                                          "Could not allocate any rx queues. "
+                                          "Aborting.\n");
                                goto queue_err;
                        } else {
-                               printk(KERN_INFO "Number of rx queues changed "
-                                      "to : %d.\n", i);
+                               netdev_info(adapter->netdev,
+                                           "Number of rx queues changed "
+                                           "to : %d.\n", i);
                                adapter->num_rx_queues = i;
                                err = 0;
                                break;
@@ -2642,15 +2641,17 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu)
                vmxnet3_adjust_rx_ring_size(adapter);
                err = vmxnet3_rq_create_all(adapter);
                if (err) {
-                       printk(KERN_ERR "%s: failed to re-create rx queues,"
-                               " error %d. Closing it.\n", netdev->name, err);
+                       netdev_err(netdev,
+                                  "failed to re-create rx queues, "
+                                  " error %d. Closing it.\n", err);
                        goto out;
                }
 
                err = vmxnet3_activate_dev(adapter);
                if (err) {
-                       printk(KERN_ERR "%s: failed to re-activate, error %d. "
-                               "Closing it\n", netdev->name, err);
+                       netdev_err(netdev,
+                                  "failed to re-activate, error %d. "
+                                  "Closing it\n", err);
                        goto out;
                }
        }
@@ -2678,10 +2679,6 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64)
        netdev->vlan_features = netdev->hw_features &
                                ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
        netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_FILTER;
-
-       netdev_info(adapter->netdev,
-               "features: sg csum vlan jf tso tsoIPv6 lro%s\n",
-               dma64 ? " highDMA" : "");
 }
 
 
@@ -2724,7 +2721,7 @@ vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
                        adapter->intr.num_intrs = vectors;
                        return 0;
                } else if (err < 0) {
-                       netdev_err(adapter->netdev,
+                       dev_err(&adapter->netdev->dev,
                                   "Failed to enable MSI-X, error: %d\n", err);
                        vectors = 0;
                } else if (err < vector_threshold) {
@@ -2733,15 +2730,16 @@ vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
                        /* If fails to enable required number of MSI-x vectors
                         * try enabling minimum number of vectors required.
                         */
-                       netdev_err(adapter->netdev,
-                                  "Failed to enable %d MSI-X, trying %d instead\n",
+                       dev_err(&adapter->netdev->dev,
+                               "Failed to enable %d MSI-X, trying %d instead\n",
                                    vectors, vector_threshold);
                        vectors = vector_threshold;
                }
        }
 
-       netdev_info(adapter->netdev,
-                   "Number of MSI-X interrupts which can be allocated are lower than min threshold required.\n");
+       dev_info(&adapter->pdev->dev,
+                "Number of MSI-X interrupts which can be allocated "
+                "is lower than min threshold required.\n");
        return err;
 }
 
@@ -2796,7 +2794,8 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
                        if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
                            || adapter->num_rx_queues != 1) {
                                adapter->share_intr = VMXNET3_INTR_TXSHARE;
-                               printk(KERN_ERR "Number of rx queues : 1\n");
+                               netdev_err(adapter->netdev,
+                                          "Number of rx queues : 1\n");
                                adapter->num_rx_queues = 1;
                                adapter->intr.num_intrs =
                                                VMXNET3_LINUX_MIN_MSIX_VECT;
@@ -2807,9 +2806,9 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
                        return;
 
                /* If we cannot allocate MSIx vectors use only one rx queue */
-               netdev_info(adapter->netdev,
-                           "Failed to enable MSI-X, error %d . Limiting #rx queues to 1, try MSI.\n",
-                           err);
+               dev_info(&adapter->pdev->dev,
+                        "Failed to enable MSI-X, error %d. "
+                        "Limiting #rx queues to 1, try MSI.\n", err);
 
                adapter->intr.type = VMXNET3_IT_MSI;
        }
@@ -2826,7 +2825,8 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
 #endif /* CONFIG_PCI_MSI */
 
        adapter->num_rx_queues = 1;
-       printk(KERN_INFO "Using INTx interrupt, #Rx queues: 1.\n");
+       dev_info(&adapter->netdev->dev,
+                "Using INTx interrupt, #Rx queues: 1.\n");
        adapter->intr.type = VMXNET3_IT_INTX;
 
        /* INT-X related setting */
@@ -2852,7 +2852,7 @@ vmxnet3_tx_timeout(struct net_device *netdev)
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        adapter->tx_timeout_count++;
 
-       printk(KERN_ERR "%s: tx hang\n", adapter->netdev->name);
+       netdev_err(adapter->netdev, "tx hang\n");
        schedule_work(&adapter->work);
        netif_wake_queue(adapter->netdev);
 }
@@ -2872,12 +2872,12 @@ vmxnet3_reset_work(struct work_struct *data)
        /* if the device is closed, we must leave it alone */
        rtnl_lock();
        if (netif_running(adapter->netdev)) {
-               printk(KERN_INFO "%s: resetting\n", adapter->netdev->name);
+               netdev_notice(adapter->netdev, "resetting\n");
                vmxnet3_quiesce_dev(adapter);
                vmxnet3_reset_dev(adapter);
                vmxnet3_activate_dev(adapter);
        } else {
-               printk(KERN_INFO "%s: already closed\n", adapter->netdev->name);
+               netdev_info(adapter->netdev, "already closed\n");
        }
        rtnl_unlock();
 
@@ -2936,8 +2936,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        num_tx_queues = rounddown_pow_of_two(num_tx_queues);
        netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter),
                                   max(num_tx_queues, num_rx_queues));
-       printk(KERN_INFO "# of Tx queues : %d, # of Rx queues : %d\n",
-              num_tx_queues, num_rx_queues);
+       dev_info(&pdev->dev,
+                "# of Tx queues : %d, # of Rx queues : %d\n",
+                num_tx_queues, num_rx_queues);
 
        if (!netdev)
                return -ENOMEM;
@@ -2952,8 +2953,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                                               sizeof(struct Vmxnet3_DriverShared),
                                               &adapter->shared_pa);
        if (!adapter->shared) {
-               printk(KERN_ERR "Failed to allocate memory for %s\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Failed to allocate memory\n");
                err = -ENOMEM;
                goto err_alloc_shared;
        }
@@ -2967,8 +2967,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                                                  &adapter->queue_desc_pa);
 
        if (!adapter->tqd_start) {
-               printk(KERN_ERR "Failed to allocate memory for %s\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Failed to allocate memory\n");
                err = -ENOMEM;
                goto err_alloc_queue_desc;
        }
@@ -2998,8 +2997,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        if (ver & 1) {
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
        } else {
-               printk(KERN_ERR "Incompatible h/w version (0x%x) for adapter"
-                      " %s\n", ver, pci_name(pdev));
+               dev_err(&pdev->dev,
+                       "Incompatible h/w version (0x%x) for adapter\n", ver);
                err = -EBUSY;
                goto err_ver;
        }
@@ -3008,8 +3007,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        if (ver & 1) {
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_UVRS, 1);
        } else {
-               printk(KERN_ERR "Incompatible upt version (0x%x) for "
-                      "adapter %s\n", ver, pci_name(pdev));
+               dev_err(&pdev->dev,
+                       "Incompatible upt version (0x%x) for adapter\n", ver);
                err = -EBUSY;
                goto err_ver;
        }
@@ -3017,11 +3016,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        SET_NETDEV_DEV(netdev, &pdev->dev);
        vmxnet3_declare_features(adapter, dma64);
 
-       adapter->dev_number = atomic_read(&devices_found);
-
-       adapter->share_intr = irq_share_mode;
-       if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE &&
-           adapter->num_tx_queues != adapter->num_rx_queues)
+       if (adapter->num_tx_queues == adapter->num_rx_queues)
+               adapter->share_intr = VMXNET3_INTR_BUDDYSHARE;
+       else
                adapter->share_intr = VMXNET3_INTR_DONTSHARE;
 
        vmxnet3_alloc_intr_resources(adapter);
@@ -3030,7 +3027,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        if (adapter->num_rx_queues > 1 &&
            adapter->intr.type == VMXNET3_IT_MSIX) {
                adapter->rss = true;
-               printk(KERN_INFO "RSS is enabled.\n");
+               netdev->hw_features |= NETIF_F_RXHASH;
+               netdev->features |= NETIF_F_RXHASH;
+               dev_dbg(&pdev->dev, "RSS is enabled.\n");
        } else {
                adapter->rss = false;
        }
@@ -3064,13 +3063,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        err = register_netdev(netdev);
 
        if (err) {
-               printk(KERN_ERR "Failed to register adapter %s\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Failed to register adapter\n");
                goto err_register;
        }
 
        vmxnet3_check_link(adapter, false);
-       atomic_inc(&devices_found);
        return 0;
 
 err_register:
@@ -3312,7 +3309,7 @@ static struct pci_driver vmxnet3_driver = {
 static int __init
 vmxnet3_init_module(void)
 {
-       printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC,
+       pr_info("%s - version %s\n", VMXNET3_DRIVER_DESC,
                VMXNET3_DRIVER_VERSION_REPORT);
        return pci_register_driver(&vmxnet3_driver);
 }
index 587a218b2345ed06eb938f5d01ed832c48dd7459..9bc542be293765a7f618b7adef6002a54ef5cf15 100644 (file)
@@ -207,7 +207,7 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
                sizeof(drvinfo->version));
 
        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
-               ETHTOOL_BUSINFO_LEN);
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = vmxnet3_get_sset_count(netdev, ETH_SS_STATS);
        drvinfo->testinfo_len = 0;
        drvinfo->eedump_len   = 0;
@@ -522,24 +522,23 @@ vmxnet3_set_ringparam(struct net_device *netdev,
                if (err) {
                        /* failed, most likely because of OOM, try default
                         * size */
-                       printk(KERN_ERR "%s: failed to apply new sizes, try the"
-                               " default ones\n", netdev->name);
+                       netdev_err(netdev, "failed to apply new sizes, "
+                                  "try the default ones\n");
                        err = vmxnet3_create_queues(adapter,
                                                    VMXNET3_DEF_TX_RING_SIZE,
                                                    VMXNET3_DEF_RX_RING_SIZE,
                                                    VMXNET3_DEF_RX_RING_SIZE);
                        if (err) {
-                               printk(KERN_ERR "%s: failed to create queues "
-                                       "with default sizes. Closing it\n",
-                                       netdev->name);
+                               netdev_err(netdev, "failed to create queues "
+                                          "with default sizes. Closing it\n");
                                goto out;
                        }
                }
 
                err = vmxnet3_activate_dev(adapter);
                if (err)
-                       printk(KERN_ERR "%s: failed to re-activate, error %d."
-                               " Closing it\n", netdev->name, err);
+                       netdev_err(netdev, "failed to re-activate, error %d."
+                                  " Closing it\n", err);
        }
 
 out:
index fc46a81ad5384969b1670114765e3df12799a256..3198384689d9fbcb5119c029706844b7d8bc86bc 100644 (file)
@@ -276,8 +276,6 @@ struct vmxnet3_rx_queue {
        struct vmxnet3_rx_ctx     rx_ctx;
        u32 qid;            /* rqID in RCD for buffer from 1st ring */
        u32 qid2;           /* rqID in RCD for buffer from 2nd ring */
-       u32 uncommitted[2]; /* # of buffers allocated since last RXPROD
-                               * update */
        struct vmxnet3_rx_buf_info     *buf_info[2];
        struct Vmxnet3_RxQueueCtrl            *shared;
        struct vmxnet3_rq_driver_stats  stats;
@@ -354,7 +352,6 @@ struct vmxnet3_adapter {
 
        unsigned long  state;    /* VMXNET3_STATE_BIT_xxx */
 
-       int dev_number;
        int share_intr;
 };
 
index def12b38cbf7002d27b83253c3be238e7e7f0802..c9c711dcd0e6bb9d7ce988f42bc7e6dd7877a37b 100644 (file)
@@ -1055,7 +1055,6 @@ int i2400m_read_mac_addr(struct i2400m *i2400m)
                result = 0;
        }
        net_dev->addr_len = ETH_ALEN;
-       memcpy(net_dev->perm_addr, ack_buf.ack_pl, ETH_ALEN);
        memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN);
 error_read_mac:
        d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result);
index 1d76ae855f077dd5d3dbb7230d392ecc7c0b3c68..cedd4d30d996dd431341bd4c2a1e947f801f2f16 100644 (file)
@@ -596,12 +596,12 @@ static void i2400m_get_drvinfo(struct net_device *net_dev,
 {
        struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
 
-       strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
-       strncpy(info->fw_version,
-               i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->fw_version, i2400m->fw_name ? : "",
+               sizeof(info->fw_version));
        if (net_dev->dev.parent)
-               strncpy(info->bus_info, dev_name(net_dev->dev.parent),
-                       sizeof(info->bus_info) - 1);
+               strlcpy(info->bus_info, dev_name(net_dev->dev.parent),
+                       sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops i2400m_ethtool_ops = {
index 080f36303a4f1887819b5ce7df994f1a916b8bc3..cd15a93d9084377ce4a8ce79d68c9b49b7fb9845 100644 (file)
@@ -346,9 +346,9 @@ static void i2400mu_get_drvinfo(struct net_device *net_dev,
        struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
        struct usb_device *udev = i2400mu->usb_dev;
 
-       strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
-       strncpy(info->fw_version,
-               i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->fw_version, i2400m->fw_name ? : "",
+               sizeof(info->fw_version));
        usb_make_path(udev, info->bus_info, sizeof(info->bus_info));
 }
 
index 30ca0a60a64c020e6b3609bff361078e03b6a89f..1d264c0f5a9b468285296e706cfef2d367678085 100644 (file)
@@ -240,13 +240,14 @@ static const struct ath_ops ath5k_common_ops = {
 * Driver Initialization *
 \***********************/
 
-static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+static void ath5k_reg_notifier(struct wiphy *wiphy,
+                              struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct ath5k_hw *ah = hw->priv;
        struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
 
-       return ath_reg_notifier_apply(wiphy, request, regulatory);
+       ath_reg_notifier_apply(wiphy, request, regulatory);
 }
 
 /********************\
index 5516a8ccc3c6809589ff1d1fd8756859f504f7e9..4225cca0f198199a4e0b0e28ee5b4748cb85a45d 100644 (file)
@@ -3492,8 +3492,8 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
                ath6kl_cfg80211_stop(vif);
 }
 
-static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
-                                     struct regulatory_request *request)
+static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
+                                      struct regulatory_request *request)
 {
        struct ath6kl *ar = wiphy_priv(wiphy);
        u32 rates[IEEE80211_NUM_BANDS];
@@ -3506,17 +3506,13 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
                   request->processed ? " processed" : "",
                   request->initiator, request->user_reg_hint_type);
 
-       /*
-        * As firmware is not able intersect regdoms, we can only listen to
-        * cellular hints.
-        */
        if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
-               return -EOPNOTSUPP;
+               return;
 
        ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
        if (ret) {
                ath6kl_err("failed to set regdomain: %d\n", ret);
-               return ret;
+               return;
        }
 
        /*
@@ -3536,10 +3532,8 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
        if (ret) {
                ath6kl_err("failed to start scan for a regdomain change: %d\n",
                           ret);
-               return ret;
+               return;
        }
-
-       return 0;
 }
 
 static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
index 3a69804f4c16e94e369691a78f612e859d86d90f..d1ff3c246a1232cd1be306fbddce97df9a3d0d28 100644 (file)
@@ -86,29 +86,25 @@ static int ath_ahb_probe(struct platform_device *pdev)
 
        if (!pdev->dev.platform_data) {
                dev_err(&pdev->dev, "no platform data specified\n");
-               ret = -EINVAL;
-               goto err_out;
+               return -EINVAL;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(&pdev->dev, "no memory resource found\n");
-               ret = -ENXIO;
-               goto err_out;
+               return -ENXIO;
        }
 
-       mem = ioremap_nocache(res->start, resource_size(res));
+       mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
        if (mem == NULL) {
                dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENOMEM;
-               goto err_out;
+               return -ENOMEM;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (res == NULL) {
                dev_err(&pdev->dev, "no IRQ resource found\n");
-               ret = -ENXIO;
-               goto err_iounmap;
+               return -ENXIO;
        }
 
        irq = res->start;
@@ -116,8 +112,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
        hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
        if (hw == NULL) {
                dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
-               ret = -ENOMEM;
-               goto err_iounmap;
+               return -ENOMEM;
        }
 
        SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -156,9 +151,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
  err_free_hw:
        ieee80211_free_hw(hw);
        platform_set_drvdata(pdev, NULL);
- err_iounmap:
-       iounmap(mem);
- err_out:
        return ret;
 }
 
@@ -168,12 +160,10 @@ static int ath_ahb_remove(struct platform_device *pdev)
 
        if (hw) {
                struct ath_softc *sc = hw->priv;
-               void __iomem *mem = sc->mem;
 
                ath9k_deinit_device(sc);
                free_irq(sc->irq, sc);
                ieee80211_free_hw(sc->hw);
-               iounmap(mem);
                platform_set_drvdata(pdev, NULL);
        }
 
index e09ec40ce71ab6c25bd801a0661c61f446496aed..7ecd40f07a7442d4769c6e0e60331f9824f3d217 100644 (file)
@@ -152,7 +152,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
        ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
                aniState->ofdmNoiseImmunityLevel,
                immunityLevel, BEACON_RSSI(ah),
-               aniState->rssiThrLow, aniState->rssiThrHigh);
+               ATH9K_ANI_RSSI_THR_LOW,
+               ATH9K_ANI_RSSI_THR_HIGH);
 
        if (!scan)
                aniState->ofdmNoiseImmunityLevel = immunityLevel;
@@ -173,7 +174,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
 
        weak_sig = entry_ofdm->ofdm_weak_signal_on;
        if (ah->opmode == NL80211_IFTYPE_STATION &&
-           BEACON_RSSI(ah) <= aniState->rssiThrHigh)
+           BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
                weak_sig = true;
 
        if (aniState->ofdmWeakSigDetect != weak_sig)
@@ -216,11 +217,11 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
 
        ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
                aniState->cckNoiseImmunityLevel, immunityLevel,
-               BEACON_RSSI(ah), aniState->rssiThrLow,
-               aniState->rssiThrHigh);
+               BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,
+               ATH9K_ANI_RSSI_THR_HIGH);
 
        if (ah->opmode == NL80211_IFTYPE_STATION &&
-           BEACON_RSSI(ah) <= aniState->rssiThrLow &&
+           BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&
            immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
                immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
 
@@ -418,9 +419,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
                return;
 
        aniState = &ah->curchan->ani;
-       if (WARN_ON(!aniState))
-               return;
-
        if (!ath9k_hw_ani_read_counters(ah))
                return;
 
@@ -489,23 +487,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 
-void ath9k_hw_ani_setup(struct ath_hw *ah)
-{
-       int i;
-
-       static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
-       static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
-       static const int coarseLow[] = { -64, -64, -64, -64, -70 };
-       static const int firpwr[] = { -78, -78, -78, -78, -80 };
-
-       for (i = 0; i < 5; i++) {
-               ah->totalSizeDesired[i] = totalSizeDesired[i];
-               ah->coarse_high[i] = coarseHigh[i];
-               ah->coarse_low[i] = coarseLow[i];
-               ah->firpwr[i] = firpwr[i];
-       }
-}
-
 void ath9k_hw_ani_init(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -531,8 +512,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 
                ani->ofdmsTurn = true;
 
-               ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
-               ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
                ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
                ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
                ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
index 1485bf5e3518851eab0e2f6531af8f5ed7118824..dddb1361039a71de9dbd205bba879e0dfcb8a14a 100644 (file)
@@ -104,7 +104,6 @@ struct ath9k_ani_default {
 };
 
 struct ar5416AniState {
-       struct ath9k_channel *c;
        u8 noiseImmunityLevel;
        u8 ofdmNoiseImmunityLevel;
        u8 cckNoiseImmunityLevel;
@@ -113,15 +112,9 @@ struct ar5416AniState {
        u8 spurImmunityLevel;
        u8 firstepLevel;
        u8 ofdmWeakSigDetect;
-       u8 cckWeakSigThreshold;
        u32 listenTime;
-       int32_t rssiThrLow;
-       int32_t rssiThrHigh;
        u32 ofdmPhyErrCount;
        u32 cckPhyErrCount;
-       int16_t pktRssi[2];
-       int16_t ofdmErrRssi[2];
-       int16_t cckErrRssi[2];
        struct ath9k_ani_default iniDef;
 };
 
@@ -147,7 +140,6 @@ struct ar5416Stats {
 
 void ath9k_enable_mib_counters(struct ath_hw *ah);
 void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
-void ath9k_hw_ani_setup(struct ath_hw *ah);
 void ath9k_hw_ani_init(struct ath_hw *ah);
 
 #endif /* ANI_H */
index f81e7fc60a364b499dfc9fba0d5ea6483ee5aba5..467ccfae2ceed8e12588a9517709c51301297e11 100644 (file)
@@ -466,7 +466,7 @@ static const u32 ar5416Bank0[][2] = {
 };
 
 static const u32 ar5416BB_RfGain[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
+       /* Addr      5G          2G        */
        {0x00009a00, 0x00000000, 0x00000000},
        {0x00009a04, 0x00000040, 0x00000040},
        {0x00009a08, 0x00000080, 0x00000080},
@@ -546,12 +546,12 @@ static const u32 ar5416Bank2[][2] = {
 };
 
 static const u32 ar5416Bank3[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
+       /* Addr      5G          2G        */
        {0x000098f0, 0x01400018, 0x01c00018},
 };
 
 static const u32 ar5416Bank6[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
+       /* Addr      5G          2G        */
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
@@ -588,7 +588,7 @@ static const u32 ar5416Bank6[][3] = {
 };
 
 static const u32 ar5416Bank6TPC[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
+       /* Addr      5G          2G        */
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
index 874186bfda41d1fd93a3838725ab3e95d3210369..fd69376ecc83a0ee89bc9da8e9472b396863cbde 100644 (file)
@@ -470,16 +470,15 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
 static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
 {
 #define ATH_ALLOC_BANK(bank, size) do { \
-               bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
-               if (!bank) { \
-                       ath_err(common, "Cannot allocate RF banks\n"); \
-                       return -ENOMEM; \
-               } \
+               bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \
+               if (!bank) \
+                       goto error; \
        } while (0);
 
        struct ath_common *common = ath9k_hw_common(ah);
 
-       BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
+       if (AR_SREV_9280_20_OR_LATER(ah))
+           return 0;
 
        ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
        ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
@@ -492,35 +491,12 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
 
        return 0;
 #undef ATH_ALLOC_BANK
+error:
+       ath_err(common, "Cannot allocate RF banks\n");
+       return -ENOMEM;
 }
 
 
-/**
- * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
- * @ah: atheros hardware struture
- * For the external AR2133/AR5133 radios banks.
- */
-static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
-{
-#define ATH_FREE_BANK(bank) do { \
-               kfree(bank); \
-               bank = NULL; \
-       } while (0);
-
-       BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
-
-       ATH_FREE_BANK(ah->analogBank0Data);
-       ATH_FREE_BANK(ah->analogBank1Data);
-       ATH_FREE_BANK(ah->analogBank2Data);
-       ATH_FREE_BANK(ah->analogBank3Data);
-       ATH_FREE_BANK(ah->analogBank6Data);
-       ATH_FREE_BANK(ah->analogBank6TPCData);
-       ATH_FREE_BANK(ah->analogBank7Data);
-       ATH_FREE_BANK(ah->bank6Temp);
-
-#undef ATH_FREE_BANK
-}
-
 /* *
  * ar5008_hw_set_rf_regs - programs rf registers based on EEPROM
  * @ah: atheros hardware structure
@@ -1380,7 +1356,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
        conf->radar_inband = 8;
 }
 
-void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
 {
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
        static const u32 ar5416_cca_regs[6] = {
@@ -1391,12 +1367,15 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
                AR_PHY_CH1_EXT_CCA,
                AR_PHY_CH2_EXT_CCA
        };
+       int ret;
+
+       ret = ar5008_hw_rf_alloc_ext_banks(ah);
+       if (ret)
+           return ret;
 
        priv_ops->rf_set_freq = ar5008_hw_set_channel;
        priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
 
-       priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks;
-       priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks;
        priv_ops->set_rf_regs = ar5008_hw_set_rf_regs;
        priv_ops->set_channel_regs = ar5008_hw_set_channel_regs;
        priv_ops->init_bb = ar5008_hw_init_bb;
@@ -1421,4 +1400,5 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
        ar5008_hw_set_nf_limits(ah);
        ar5008_hw_set_radar_conf(ah);
        memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
+       return 0;
 }
index ea4a230997acc7c34c3e944a9ddf4d8c9e65f914..59524e1d4678c5fd0eb4a73979648cc76c2d353b 100644 (file)
@@ -460,7 +460,7 @@ static const u32 ar5416Common_9100[][2] = {
 };
 
 static const u32 ar5416Bank6_9100[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
+       /* Addr      5G          2G        */
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
@@ -497,7 +497,7 @@ static const u32 ar5416Bank6_9100[][3] = {
 };
 
 static const u32 ar5416Bank6TPC_9100[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
+       /* Addr      5G          2G        */
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
        {0x0000989c, 0x00000000, 0x00000000},
index 648da3e885e9250080f0403ebb74437b02b0e892..f053d978540e712658124e4e884273bf423cb833 100644 (file)
 
 /* General hardware code for the A5008/AR9001/AR9002 hadware families */
 
-static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
+static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
 {
        if (AR_SREV_9271(ah)) {
                INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271);
                INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271);
                INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg);
-               return;
+               return 0;
        }
 
        if (ah->config.pcie_clock_req)
@@ -102,9 +102,9 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
                u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns;
                u32 *data;
 
-               data = kmalloc(size, GFP_KERNEL);
+               data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
                if (!data)
-                       return;
+                       return -ENOMEM;
 
                memcpy(data, addac->ia_array, size);
                addac->ia_array = data;
@@ -120,6 +120,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
                INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
                       ar9287Common_japan_2484_cck_fir_coeff_9287_1_1);
        }
+       return 0;
 }
 
 static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
@@ -409,22 +410,30 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
 }
 
 /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
-void ar9002_hw_attach_ops(struct ath_hw *ah)
+int ar9002_hw_attach_ops(struct ath_hw *ah)
 {
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+       int ret;
+
+       ret = ar9002_hw_init_mode_regs(ah);
+       if (ret)
+               return ret;
 
-       priv_ops->init_mode_regs = ar9002_hw_init_mode_regs;
        priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
 
        ops->config_pci_powersave = ar9002_hw_configpcipowersave;
 
-       ar5008_hw_attach_phy_ops(ah);
+       ret = ar5008_hw_attach_phy_ops(ah);
+       if (ret)
+               return ret;
+
        if (AR_SREV_9280_20_OR_LATER(ah))
                ar9002_hw_attach_phy_ops(ah);
 
        ar9002_hw_attach_calib_ops(ah);
        ar9002_hw_attach_mac_ops(ah);
+       return 0;
 }
 
 void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
index 846dd7974eb8ff4c571574d5f26dcd2c1ed98a64..f4003512d8d57e223c59fc10477ad9f99d262ede 100644 (file)
@@ -555,14 +555,73 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
        REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
 }
 
+static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
+                                   struct ath_spec_scan *param)
+{
+       u8 count;
+
+       if (!param->enabled) {
+               REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                           AR_PHY_SPECTRAL_SCAN_ENABLE);
+               return;
+       }
+       REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+       REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+       if (param->short_repeat)
+               REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                           AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+       else
+               REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                           AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+       /* on AR92xx, the highest bit of count will make the the chip send
+        * spectral samples endlessly. Check if this really was intended,
+        * and fix otherwise.
+        */
+       count = param->count;
+       if (param->endless)
+               count = 0x80;
+       else if (count & 0x80)
+               count = 0x7f;
+
+       REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+                     AR_PHY_SPECTRAL_SCAN_COUNT, count);
+       REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+                     AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+       REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+                     AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+       return;
+}
+
+static void ar9002_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+       REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+       /* Activate spectral scan */
+       REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                   AR_PHY_SPECTRAL_SCAN_ACTIVE);
+}
+
+static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       /* Poll for spectral scan complete */
+       if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+                          AR_PHY_SPECTRAL_SCAN_ACTIVE,
+                          0, AH_WAIT_TIMEOUT)) {
+               ath_err(common, "spectral scan wait failed\n");
+               return;
+       }
+}
+
 void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
 {
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 
        priv_ops->set_rf_regs = NULL;
-       priv_ops->rf_alloc_ext_banks = NULL;
-       priv_ops->rf_free_ext_banks = NULL;
        priv_ops->rf_set_freq = ar9002_hw_set_channel;
        priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
        priv_ops->olc_init = ar9002_olc_init;
@@ -571,6 +630,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
 
        ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
        ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+       ops->spectral_scan_config = ar9002_hw_spectral_scan_config;
+       ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger;
+       ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait;
 
        ar9002_hw_set_nf_limits(ah);
 }
index 262e1e036fd730fe63f273001aff016ac600e0cf..db5ffada221718f76f6a1dfeabfbb5c6ed2929ef 100644 (file)
@@ -744,6 +744,186 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
+static const u32 ar9300Modes_mixed_ob_db_tx_gain_table_2p2[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
+       {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
+       {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+       {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
+       {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
+       {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
+       {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20},
+       {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20},
+       {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
+       {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
+       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
+       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
+       {0x0000a544, 0x52022470, 0x52022470, 0x3b001861, 0x3b001861},
+       {0x0000a548, 0x55022490, 0x55022490, 0x3e001a81, 0x3e001a81},
+       {0x0000a54c, 0x59022492, 0x59022492, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d022692, 0x5d022692, 0x44001c84, 0x44001c84},
+       {0x0000a554, 0x61022892, 0x61022892, 0x48001ce3, 0x48001ce3},
+       {0x0000a558, 0x65024890, 0x65024890, 0x4c001ce5, 0x4c001ce5},
+       {0x0000a55c, 0x69024892, 0x69024892, 0x50001ce9, 0x50001ce9},
+       {0x0000a560, 0x6e024c92, 0x6e024c92, 0x54001ceb, 0x54001ceb},
+       {0x0000a564, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+       {0x0000a56c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+       {0x0000a570, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+       {0x0000a574, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+       {0x0000a578, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+       {0x0000a57c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+       {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+       {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
+       {0x0000a598, 0x21802220, 0x21802220, 0x15800402, 0x15800402},
+       {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
+       {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
+       {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
+       {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
+       {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
+       {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
+       {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
+       {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
+       {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
+       {0x0000a5c4, 0x52822470, 0x52822470, 0x3b801861, 0x3b801861},
+       {0x0000a5c8, 0x55822490, 0x55822490, 0x3e801a81, 0x3e801a81},
+       {0x0000a5cc, 0x59822492, 0x59822492, 0x42801a83, 0x42801a83},
+       {0x0000a5d0, 0x5d822692, 0x5d822692, 0x44801c84, 0x44801c84},
+       {0x0000a5d4, 0x61822892, 0x61822892, 0x48801ce3, 0x48801ce3},
+       {0x0000a5d8, 0x65824890, 0x65824890, 0x4c801ce5, 0x4c801ce5},
+       {0x0000a5dc, 0x69824892, 0x69824892, 0x50801ce9, 0x50801ce9},
+       {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x54801ceb, 0x54801ceb},
+       {0x0000a5e4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+       {0x0000a5e8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+       {0x0000a5ec, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+       {0x0000a5f0, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+       {0x0000a5f4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+       {0x0000a5f8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+       {0x0000a5fc, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+       {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+       {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+       {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+       {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+       {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+       {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+       {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+       {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+       {0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+       {0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+       {0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Modes_type5_tx_gain_table_2p2[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+       {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+       {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+       {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+       {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+       {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+       {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+       {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+       {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+       {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+       {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+       {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+       {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+       {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+       {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
+       {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
+       {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+       {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+       {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+       {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+       {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+       {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
 static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
        /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
index 56317b0fb6b692f3f9ae20b8ba681ec18371788f..4cc13940c8950d2a7ad2a3fdf1a092ac3736a7d5 100644 (file)
@@ -32,7 +32,6 @@ struct coeff {
 
 enum ar9003_cal_types {
        IQ_MISMATCH_CAL = BIT(0),
-       TEMP_COMP_CAL = BIT(1),
 };
 
 static void ar9003_hw_setup_calibration(struct ath_hw *ah,
@@ -49,7 +48,7 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
                 */
                REG_RMW_FIELD(ah, AR_PHY_TIMING4,
                              AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
-               currCal->calData->calCountMax);
+                             currCal->calData->calCountMax);
                REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
 
                ath_dbg(common, CALIBRATE,
@@ -58,14 +57,8 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
                /* Kick-off cal */
                REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
                break;
-       case TEMP_COMP_CAL:
-               REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
-                             AR_PHY_65NM_CH0_THERM_LOCAL, 1);
-               REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
-                             AR_PHY_65NM_CH0_THERM_START, 1);
-
-               ath_dbg(common, CALIBRATE,
-                       "starting Temperature Compensation Calibration\n");
+       default:
+               ath_err(common, "Invalid calibration type\n");
                break;
        }
 }
@@ -323,6 +316,14 @@ static const struct ath9k_percal_data iq_cal_single_sample = {
 static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
 {
        ah->iq_caldata.calData = &iq_cal_single_sample;
+
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               ah->enabled_cals |= TX_IQ_CAL;
+               if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))
+                       ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
+       }
+
+       ah->supp_cals = IQ_MISMATCH_CAL;
 }
 
 /*
@@ -959,22 +960,68 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
                      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
 }
 
+static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
+{
+       int i;
+
+       if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
+               return;
+
+       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+               if (!(ah->rxchainmask & (1 << i)))
+                       continue;
+               ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
+       }
+}
+
+static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
+{
+       u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
+                                         AR_PHY_CL_TAB_1,
+                                         AR_PHY_CL_TAB_2 };
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
+       bool txclcal_done = false;
+       int i, j;
+
+       if (!caldata || !(ah->enabled_cals & TX_CL_CAL))
+               return;
+
+       txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
+                         AR_PHY_AGC_CONTROL_CLC_SUCCESS);
+
+       if (caldata->done_txclcal_once) {
+               for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+                       if (!(ah->txchainmask & (1 << i)))
+                               continue;
+                       for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+                               REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
+                                         caldata->tx_clcal[i][j]);
+               }
+       } else if (is_reusable && txclcal_done) {
+               for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+                       if (!(ah->txchainmask & (1 << i)))
+                               continue;
+                       for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+                               caldata->tx_clcal[i][j] =
+                                       REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
+               }
+               caldata->done_txclcal_once = true;
+       }
+}
+
 static bool ar9003_hw_init_cal(struct ath_hw *ah,
                               struct ath9k_channel *chan)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_cal_data *caldata = ah->caldata;
-       bool txiqcal_done = false, txclcal_done = false;
+       bool txiqcal_done = false;
        bool is_reusable = true, status = true;
-       bool run_rtt_cal = false, run_agc_cal;
+       bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
        bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
        u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
                                          AR_PHY_AGC_CONTROL_FLTR_CAL   |
                                          AR_PHY_AGC_CONTROL_PKDET_CAL;
-       int i, j;
-       u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
-                                         AR_PHY_CL_TAB_1,
-                                         AR_PHY_CL_TAB_2 };
 
        ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
 
@@ -1014,7 +1061,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
                }
        }
 
-       if (!(ah->enabled_cals & TX_IQ_CAL))
+       if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||
+           !(ah->enabled_cals & TX_IQ_CAL))
                goto skip_tx_iqcal;
 
        /* Do Tx IQ Calibration */
@@ -1034,21 +1082,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
                        REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
                                    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
                txiqcal_done = run_agc_cal = true;
-               goto skip_tx_iqcal;
-       } else if (caldata && !caldata->done_txiqcal_once)
+       } else if (caldata && !caldata->done_txiqcal_once) {
                run_agc_cal = true;
+               sep_iq_cal = true;
+       }
 
+skip_tx_iqcal:
        if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
                ar9003_mci_init_cal_req(ah, &is_reusable);
 
-       if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
+       if (sep_iq_cal) {
                txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
                REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
                udelay(5);
                REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
        }
 
-skip_tx_iqcal:
        if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
                /* Calibrate the AGC */
                REG_WRITE(ah, AR_PHY_AGC_CONTROL,
@@ -1059,14 +1108,8 @@ skip_tx_iqcal:
                status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
                                       AR_PHY_AGC_CONTROL_CAL,
                                       0, AH_WAIT_TIMEOUT);
-               if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
-                       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-                               if (!(ah->rxchainmask & (1 << i)))
-                                       continue;
-                               ar9003_hw_manual_peak_cal(ah, i,
-                                                         IS_CHAN_2GHZ(chan));
-                       }
-               }
+
+               ar9003_hw_do_manual_peak_cal(ah, chan);
        }
 
        if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
@@ -1091,31 +1134,7 @@ skip_tx_iqcal:
        else if (caldata && caldata->done_txiqcal_once)
                ar9003_hw_tx_iq_cal_reload(ah);
 
-#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
-       if (caldata && (ah->enabled_cals & TX_CL_CAL)) {
-               txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
-                                          AR_PHY_AGC_CONTROL_CLC_SUCCESS);
-               if (caldata->done_txclcal_once) {
-                       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-                               if (!(ah->txchainmask & (1 << i)))
-                                       continue;
-                               for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
-                                       REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
-                                                 caldata->tx_clcal[i][j]);
-                       }
-               } else if (is_reusable && txclcal_done) {
-                       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-                               if (!(ah->txchainmask & (1 << i)))
-                                       continue;
-                               for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
-                                       caldata->tx_clcal[i][j] =
-                                               REG_READ(ah,
-                                                 CL_TAB_ENTRY(cl_idx[i]));
-                       }
-                       caldata->done_txclcal_once = true;
-               }
-       }
-#undef CL_TAB_ENTRY
+       ar9003_hw_cl_cal_post_proc(ah, is_reusable);
 
        if (run_rtt_cal && caldata) {
                if (is_reusable) {
@@ -1133,20 +1152,10 @@ skip_tx_iqcal:
 
        /* Initialize list pointers */
        ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
-       ah->supp_cals = IQ_MISMATCH_CAL;
-
-       if (ah->supp_cals & IQ_MISMATCH_CAL) {
-               INIT_CAL(&ah->iq_caldata);
-               INSERT_CAL(ah, &ah->iq_caldata);
-               ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
-       }
 
-       if (ah->supp_cals & TEMP_COMP_CAL) {
-               INIT_CAL(&ah->tempCompCalData);
-               INSERT_CAL(ah, &ah->tempCompCalData);
-               ath_dbg(common, CALIBRATE,
-                       "enabling Temperature Compensation Calibration\n");
-       }
+       INIT_CAL(&ah->iq_caldata);
+       INSERT_CAL(ah, &ah->iq_caldata);
+       ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
 
        /* Initialize current pointer to first element in list */
        ah->cal_list_curr = ah->cal_list;
index 562186ca9b5248a26c7cb957357d80f0d5f162fb..881e989ea4701b0dc98c3229e196b5b2b2a5b70f 100644 (file)
@@ -4586,14 +4586,14 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
        return 0;
 }
 
-static int ar9003_hw_power_control_override(struct ath_hw *ah,
-                                           int frequency,
-                                           int *correction,
-                                           int *voltage, int *temperature)
+static void ar9003_hw_power_control_override(struct ath_hw *ah,
+                                            int frequency,
+                                            int *correction,
+                                            int *voltage, int *temperature)
 {
-       int tempSlope = 0;
+       int temp_slope = 0, temp_slope1 = 0, temp_slope2 = 0;
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
-       int f[8], t[8], i;
+       int f[8], t[8], t1[3], t2[3], i;
 
        REG_RMW(ah, AR_PHY_TPC_11_B0,
                (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
@@ -4624,38 +4624,108 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah,
         * enable temperature compensation
         * Need to use register names
         */
-       if (frequency < 4000)
-               tempSlope = eep->modalHeader2G.tempSlope;
-       else if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
-               for (i = 0; i < 8; i++) {
-                       t[i] = eep->base_ext1.tempslopextension[i];
-                       f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
+       if (frequency < 4000) {
+               temp_slope = eep->modalHeader2G.tempSlope;
+       } else {
+               if (AR_SREV_9550(ah)) {
+                       t[0] = eep->base_ext1.tempslopextension[2];
+                       t1[0] = eep->base_ext1.tempslopextension[3];
+                       t2[0] = eep->base_ext1.tempslopextension[4];
+                       f[0] = 5180;
+
+                       t[1] = eep->modalHeader5G.tempSlope;
+                       t1[1] = eep->base_ext1.tempslopextension[0];
+                       t2[1] = eep->base_ext1.tempslopextension[1];
+                       f[1] = 5500;
+
+                       t[2] = eep->base_ext1.tempslopextension[5];
+                       t1[2] = eep->base_ext1.tempslopextension[6];
+                       t2[2] = eep->base_ext1.tempslopextension[7];
+                       f[2] = 5785;
+
+                       temp_slope = ar9003_hw_power_interpolate(frequency,
+                                                                f, t, 3);
+                       temp_slope1 = ar9003_hw_power_interpolate(frequency,
+                                                                  f, t1, 3);
+                       temp_slope2 = ar9003_hw_power_interpolate(frequency,
+                                                                  f, t2, 3);
+
+                       goto tempslope;
                }
-               tempSlope = ar9003_hw_power_interpolate((s32) frequency,
-                                                       f, t, 8);
-       } else if (eep->base_ext2.tempSlopeLow != 0) {
-               t[0] = eep->base_ext2.tempSlopeLow;
-               f[0] = 5180;
-               t[1] = eep->modalHeader5G.tempSlope;
-               f[1] = 5500;
-               t[2] = eep->base_ext2.tempSlopeHigh;
-               f[2] = 5785;
-               tempSlope = ar9003_hw_power_interpolate((s32) frequency,
-                                                       f, t, 3);
-       } else
-               tempSlope = eep->modalHeader5G.tempSlope;
 
-       REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
+               if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
+                       for (i = 0; i < 8; i++) {
+                               t[i] = eep->base_ext1.tempslopextension[i];
+                               f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
+                       }
+                       temp_slope = ar9003_hw_power_interpolate((s32) frequency,
+                                                                f, t, 8);
+               } else if (eep->base_ext2.tempSlopeLow != 0) {
+                       t[0] = eep->base_ext2.tempSlopeLow;
+                       f[0] = 5180;
+                       t[1] = eep->modalHeader5G.tempSlope;
+                       f[1] = 5500;
+                       t[2] = eep->base_ext2.tempSlopeHigh;
+                       f[2] = 5785;
+                       temp_slope = ar9003_hw_power_interpolate((s32) frequency,
+                                                                f, t, 3);
+               } else {
+                       temp_slope = eep->modalHeader5G.tempSlope;
+               }
+       }
+
+tempslope:
+       if (AR_SREV_9550(ah)) {
+               /*
+                * AR955x has tempSlope register for each chain.
+                * Check whether temp_compensation feature is enabled or not.
+                */
+               if (eep->baseEepHeader.featureEnable & 0x1) {
+                       if (frequency < 4000) {
+                               REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+                                             AR_PHY_TPC_19_ALPHA_THERM,
+                                             eep->base_ext2.tempSlopeLow);
+                               REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+                                             AR_PHY_TPC_19_ALPHA_THERM,
+                                             temp_slope);
+                               REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+                                             AR_PHY_TPC_19_ALPHA_THERM,
+                                             eep->base_ext2.tempSlopeHigh);
+                       } else {
+                               REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+                                             AR_PHY_TPC_19_ALPHA_THERM,
+                                             temp_slope);
+                               REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+                                             AR_PHY_TPC_19_ALPHA_THERM,
+                                             temp_slope1);
+                               REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+                                             AR_PHY_TPC_19_ALPHA_THERM,
+                                             temp_slope2);
+                       }
+               } else {
+                       /*
+                        * If temp compensation is not enabled,
+                        * set all registers to 0.
+                        */
+                       REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+                                     AR_PHY_TPC_19_ALPHA_THERM, 0);
+                       REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+                                     AR_PHY_TPC_19_ALPHA_THERM, 0);
+                       REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+                                     AR_PHY_TPC_19_ALPHA_THERM, 0);
+               }
+       } else {
+               REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+                             AR_PHY_TPC_19_ALPHA_THERM, temp_slope);
+       }
 
        if (AR_SREV_9462_20(ah))
                REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
-                             AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope);
+                             AR_PHY_TPC_19_B1_ALPHA_THERM, temp_slope);
 
 
        REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE,
                      temperature[0]);
-
-       return 0;
 }
 
 /* Apply the recorded correction values. */
index 59bf5f31e212c07bfef14251384aa3f5d2de0c8b..a3523c969a3ace778b3daa4aabd2ac2d85761390 100644 (file)
@@ -507,28 +507,59 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah)
        else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9580_1p0_mixed_ob_db_tx_gain_table);
+       else
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9300Modes_mixed_ob_db_tx_gain_table_2p2);
+}
+
+static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
+{
+       if (AR_SREV_9485_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9485Modes_green_ob_db_tx_gain_1_1);
+       else if (AR_SREV_9340(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9340Modes_ub124_tx_gain_table_1p0);
+       else if (AR_SREV_9580(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9580_1p0_type5_tx_gain_table);
+       else if (AR_SREV_9300_22(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9300Modes_type5_tx_gain_table_2p2);
 }
 
+static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)
+{
+       if (AR_SREV_9340(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0);
+       else if (AR_SREV_9485_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9485Modes_green_spur_ob_db_tx_gain_1_1);
+       else if (AR_SREV_9580(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9580_1p0_type6_tx_gain_table);
+}
+
+typedef void (*ath_txgain_tab)(struct ath_hw *ah);
+
 static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 {
-       switch (ar9003_hw_get_tx_gain_idx(ah)) {
-       case 0:
-       default:
-               ar9003_tx_gain_table_mode0(ah);
-               break;
-       case 1:
-               ar9003_tx_gain_table_mode1(ah);
-               break;
-       case 2:
-               ar9003_tx_gain_table_mode2(ah);
-               break;
-       case 3:
-               ar9003_tx_gain_table_mode3(ah);
-               break;
-       case 4:
-               ar9003_tx_gain_table_mode4(ah);
-               break;
-       }
+       static const ath_txgain_tab modes[] = {
+               ar9003_tx_gain_table_mode0,
+               ar9003_tx_gain_table_mode1,
+               ar9003_tx_gain_table_mode2,
+               ar9003_tx_gain_table_mode3,
+               ar9003_tx_gain_table_mode4,
+               ar9003_tx_gain_table_mode5,
+               ar9003_tx_gain_table_mode6,
+       };
+       int idx = ar9003_hw_get_tx_gain_idx(ah);
+
+       if (idx >= ARRAY_SIZE(modes))
+               idx = 0;
+
+       modes[idx](ah);
 }
 
 static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
@@ -673,7 +704,7 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 
-       priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
+       ar9003_hw_init_mode_regs(ah);
        priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
 
        ops->config_pci_powersave = ar9003_hw_configpcipowersave;
index 3afc24bde6d65d88a0d469abb0ef73d93856edcb..2bf6548dd143c420f1a5d7372040b5638dd8ad38 100644 (file)
@@ -68,7 +68,7 @@ static const int m2ThreshExt_off = 127;
 static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
 {
        u16 bMode, fracMode = 0, aModeRefSel = 0;
-       u32 freq, channelSel = 0, reg32 = 0;
+       u32 freq, chan_frac, div, channelSel = 0, reg32 = 0;
        struct chan_centers centers;
        int loadSynthChannel;
 
@@ -77,9 +77,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
 
        if (freq < 4800) {     /* 2 GHz, fractional mode */
                if (AR_SREV_9330(ah)) {
-                       u32 chan_frac;
-                       u32 div;
-
                        if (ah->is_clk_25mhz)
                                div = 75;
                        else
@@ -89,34 +86,40 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
                        chan_frac = (((freq * 4) % div) * 0x20000) / div;
                        channelSel = (channelSel << 17) | chan_frac;
                } else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
-                       u32 chan_frac;
-
                        /*
-                        * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
+                        * freq_ref = 40 / (refdiva >> amoderefsel);
+                        * where refdiva=1 and amoderefsel=0
                         * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
                         * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
                         */
                        channelSel = (freq * 4) / 120;
                        chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
                        channelSel = (channelSel << 17) | chan_frac;
-               } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
+               } else if (AR_SREV_9340(ah)) {
                        if (ah->is_clk_25mhz) {
-                               u32 chan_frac;
-
                                channelSel = (freq * 2) / 75;
                                chan_frac = (((freq * 2) % 75) * 0x20000) / 75;
                                channelSel = (channelSel << 17) | chan_frac;
-                       } else
+                       } else {
                                channelSel = CHANSEL_2G(freq) >> 1;
-               } else
+                       }
+               } else if (AR_SREV_9550(ah)) {
+                       if (ah->is_clk_25mhz)
+                               div = 75;
+                       else
+                               div = 120;
+
+                       channelSel = (freq * 4) / div;
+                       chan_frac = (((freq * 4) % div) * 0x20000) / div;
+                       channelSel = (channelSel << 17) | chan_frac;
+               } else {
                        channelSel = CHANSEL_2G(freq);
+               }
                /* Set to 2G mode */
                bMode = 1;
        } else {
                if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) &&
                    ah->is_clk_25mhz) {
-                       u32 chan_frac;
-
                        channelSel = freq / 75;
                        chan_frac = ((freq % 75) * 0x20000) / 75;
                        channelSel = (channelSel << 17) | chan_frac;
@@ -1437,6 +1440,67 @@ set_rfmode:
        return 0;
 }
 
+static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
+                                          struct ath_spec_scan *param)
+{
+       u8 count;
+
+       if (!param->enabled) {
+               REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                           AR_PHY_SPECTRAL_SCAN_ENABLE);
+               return;
+       }
+
+       REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+       REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+       /* on AR93xx and newer, count = 0 will make the the chip send
+        * spectral samples endlessly. Check if this really was intended,
+        * and fix otherwise.
+        */
+       count = param->count;
+       if (param->endless)
+               count = 0;
+       else if (param->count == 0)
+               count = 1;
+
+       if (param->short_repeat)
+               REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                           AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+       else
+               REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                           AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+       REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+                     AR_PHY_SPECTRAL_SCAN_COUNT, count);
+       REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+                     AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+       REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+                     AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+       return;
+}
+
+static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+       /* Activate spectral scan */
+       REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+                   AR_PHY_SPECTRAL_SCAN_ACTIVE);
+}
+
+static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       /* Poll for spectral scan complete */
+       if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+                          AR_PHY_SPECTRAL_SCAN_ACTIVE,
+                          0, AH_WAIT_TIMEOUT)) {
+               ath_err(common, "spectral scan wait failed\n");
+               return;
+       }
+}
+
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
 {
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -1470,6 +1534,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
        ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
        ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
        ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
+       ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
+       ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
+       ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;
 
        ar9003_hw_set_nf_limits(ah);
        ar9003_hw_set_radar_conf(ah);
index 10795629848871cbd2e34df016102fd9cfe920f2..e71774196c01bbf7fa6f3a33b1789556fc63ae9a 100644 (file)
 #define AR_PHY_TPC_5_B2          (AR_SM2_BASE + 0x208)
 #define AR_PHY_TPC_6_B2          (AR_SM2_BASE + 0x20c)
 #define AR_PHY_TPC_11_B2         (AR_SM2_BASE + 0x220)
-#define AR_PHY_PDADC_TAB_2       (AR_SM2_BASE + 0x240)
+#define AR_PHY_TPC_19_B2         (AR_SM2_BASE + 0x240)
 #define AR_PHY_TX_IQCAL_STATUS_B2   (AR_SM2_BASE + 0x48c)
 #define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i)    (AR_SM2_BASE + 0x450 + ((_i) << 2))
 
index f69d292bdc027403aa7400bce554899a41462a0b..25db9215985aa1519e0901cb698b312811d6dc91 100644 (file)
@@ -1172,6 +1172,106 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
        {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
 };
 
+static const u32 ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
+       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
+       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
+       {0x0000a394, 0x00000444, 0x00000444, 0x00000404, 0x00000404},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x02000001, 0x02000001},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x05000003, 0x05000003},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0a000005, 0x0a000005},
+       {0x0000a510, 0x16000220, 0x16000220, 0x0e000201, 0x0e000201},
+       {0x0000a514, 0x1c000223, 0x1c000223, 0x11000203, 0x11000203},
+       {0x0000a518, 0x21002220, 0x21002220, 0x14000401, 0x14000401},
+       {0x0000a51c, 0x27002223, 0x27002223, 0x18000403, 0x18000403},
+       {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000602, 0x1b000602},
+       {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000802, 0x1f000802},
+       {0x0000a528, 0x34022225, 0x34022225, 0x21000620, 0x21000620},
+       {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x25000820, 0x25000820},
+       {0x0000a530, 0x3e02222c, 0x3e02222c, 0x29000822, 0x29000822},
+       {0x0000a534, 0x4202242a, 0x4202242a, 0x2d000824, 0x2d000824},
+       {0x0000a538, 0x4702244a, 0x4702244a, 0x30000828, 0x30000828},
+       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x3400082a, 0x3400082a},
+       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38000849, 0x38000849},
+       {0x0000a544, 0x5302266c, 0x5302266c, 0x3b000a2c, 0x3b000a2c},
+       {0x0000a548, 0x5702286c, 0x5702286c, 0x3e000e2b, 0x3e000e2b},
+       {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42000e2d, 0x42000e2d},
+       {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4500124a, 0x4500124a},
+       {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4900124c, 0x4900124c},
+       {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c00126c, 0x4c00126c},
+       {0x0000a55c, 0x7002708c, 0x7002708c, 0x4f00128c, 0x4f00128c},
+       {0x0000a560, 0x7302b08a, 0x7302b08a, 0x52001290, 0x52001290},
+       {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+       {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+       {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+       {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+       {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+       {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+       {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+       {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06800003, 0x06800003, 0x02800001, 0x02800001},
+       {0x0000a588, 0x0a800020, 0x0a800020, 0x05800003, 0x05800003},
+       {0x0000a58c, 0x10800023, 0x10800023, 0x0a800005, 0x0a800005},
+       {0x0000a590, 0x16800220, 0x16800220, 0x0e800201, 0x0e800201},
+       {0x0000a594, 0x1c800223, 0x1c800223, 0x11800203, 0x11800203},
+       {0x0000a598, 0x21820220, 0x21820220, 0x14800401, 0x14800401},
+       {0x0000a59c, 0x27820223, 0x27820223, 0x18800403, 0x18800403},
+       {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800602, 0x1b800602},
+       {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800802, 0x1f800802},
+       {0x0000a5a8, 0x34822225, 0x34822225, 0x21800620, 0x21800620},
+       {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x25800820, 0x25800820},
+       {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x29800822, 0x29800822},
+       {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2d800824, 0x2d800824},
+       {0x0000a5b8, 0x4782244a, 0x4782244a, 0x30800828, 0x30800828},
+       {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x3480082a, 0x3480082a},
+       {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38800849, 0x38800849},
+       {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b800a2c, 0x3b800a2c},
+       {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e800e2b, 0x3e800e2b},
+       {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42800e2d, 0x42800e2d},
+       {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4580124a, 0x4580124a},
+       {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4980124c, 0x4980124c},
+       {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c80126c, 0x4c80126c},
+       {0x0000a5dc, 0x7086308c, 0x7086308c, 0x4f80128c, 0x4f80128c},
+       {0x0000a5e0, 0x738a308a, 0x738a308a, 0x52801290, 0x52801290},
+       {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+       {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+       {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+       {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+       {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+       {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+       {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01404000, 0x01404000, 0x01404501, 0x01404501},
+       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x02008802, 0x02008802, 0x01404501, 0x01404501},
+       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x03c0cf02, 0x03c0cf02},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03c0cf03, 0x03c0cf03},
+       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04011004, 0x04011004},
+       {0x0000a62c, 0x03810c03, 0x03810c03, 0x05419405, 0x05419405},
+       {0x0000a630, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+       {0x0000a634, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+       {0x0000a638, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+       {0x0000a63c, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
+       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
+       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
+       {0x00016044, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
+       {0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
+       {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
+       {0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000},
+       {0x00016444, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
+       {0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
+};
+
 static const u32 ar9340_1p0_mac_core[][2] = {
        /* Addr      allmodes  */
        {0x00000008, 0x00000000},
index a3710f3bb90c5b0fe8a02cc26455ec31b3697162..712f415b8c0861165ab2a2ee74cbea853788295b 100644 (file)
@@ -260,6 +260,79 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
        {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
 };
 
+static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+       {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
+       {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
+       {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
+       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203},
+       {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
+       {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
+       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
+       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604},
+       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605},
+       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04},
+       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06},
+       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24},
+       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21},
+       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20},
+       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20},
+       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
+       {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
+       {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
+       {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
 static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
@@ -450,6 +523,79 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
 
 #define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
 
+static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+       {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
+       {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
+       {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
+       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x07000203, 0x07000203},
+       {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
+       {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
+       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
+       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x14000406, 0x14000406},
+       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1800040a, 0x1800040a},
+       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000460, 0x1c000460},
+       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x22000463, 0x22000463},
+       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x26000465, 0x26000465},
+       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2e0006e0, 0x2e0006e0},
+       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0},
+       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0},
+       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3},
+       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5},
+       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6},
+       {0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec},
+       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1},
+       {0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3},
+       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed},
+       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1},
+       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3},
+       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5},
+       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6},
+       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+       {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
+       {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
+       {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
+       {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
 static const u32 ar9485_1_1[][2] = {
        /* Addr      allmodes  */
        {0x0000a580, 0x00000000},
index df97f21c52dc1d9a895e4b3a4ce466861f03b792..ccc5b6c99add76617b4b990e106bd57be0d1f09f 100644 (file)
 static const u32 ar955x_1p0_radio_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330},
-       {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a},
-       {0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800},
-       {0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a},
-       {0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+       {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a},
+       {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24647c00, 0x24647c00},
+       {0x000160b0, 0x01885f52, 0x01885f52, 0x01885f52, 0x01885f52},
+       {0x00016104, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
        {0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
        {0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
-       {0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+       {0x00016504, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
        {0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
        {0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
-       {0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+       {0x00016904, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
        {0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
        {0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
 };
@@ -69,15 +69,15 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
        {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0},
        {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
        {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
-       {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+       {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
        {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
        {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
        {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
        {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
        {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
-       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
        {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
-       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
        {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
        {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
        {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
@@ -125,7 +125,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
        {0x00016094, 0x00000000},
        {0x000160a0, 0x0a108ffe},
        {0x000160a4, 0x812fc370},
-       {0x000160a8, 0x423c8000},
+       {0x000160a8, 0x423c8100},
        {0x000160b4, 0x92480080},
        {0x000160c0, 0x006db6d0},
        {0x000160c4, 0x6db6db60},
@@ -134,7 +134,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
        {0x00016100, 0x11999601},
        {0x00016108, 0x00080010},
        {0x00016144, 0x02084080},
-       {0x00016148, 0x000080c0},
+       {0x00016148, 0x00008040},
        {0x00016280, 0x01800804},
        {0x00016284, 0x00038dc5},
        {0x00016288, 0x00000000},
@@ -178,7 +178,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
        {0x00016500, 0x11999601},
        {0x00016508, 0x00080010},
        {0x00016544, 0x02084080},
-       {0x00016548, 0x000080c0},
+       {0x00016548, 0x00008040},
        {0x00016780, 0x00000000},
        {0x00016784, 0x00000000},
        {0x00016788, 0x00400705},
@@ -218,7 +218,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
        {0x00016900, 0x11999601},
        {0x00016908, 0x00080010},
        {0x00016944, 0x02084080},
-       {0x00016948, 0x000080c0},
+       {0x00016948, 0x00008040},
        {0x00016b80, 0x00000000},
        {0x00016b84, 0x00000000},
        {0x00016b88, 0x00400705},
@@ -245,9 +245,9 @@ static const u32 ar955x_1p0_radio_core[][2] = {
 
 static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = {
        /* Addr      5G_HT20_L   5G_HT40_L   5G_HT20_M   5G_HT40_M   5G_HT20_H   5G_HT40_H   2G_HT40     2G_HT20  */
-       {0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
-       {0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
-       {0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+       {0x0000a2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+       {0x0000a2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+       {0x0000a2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
        {0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
        {0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da},
        {0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000},
@@ -256,63 +256,63 @@ static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = {
        {0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006},
        {0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a},
        {0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c},
-       {0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e},
-       {0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064},
-       {0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242},
-       {0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229},
-       {0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2},
-       {0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203},
-       {0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803},
-       {0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881},
-       {0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809},
-       {0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814},
-       {0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c},
-       {0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e},
-       {0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812},
-       {0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884},
-       {0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84},
-       {0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69},
-       {0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4},
-       {0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3},
-       {0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5},
-       {0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced},
-       {0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4},
-       {0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4},
-       {0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4},
-       {0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4},
-       {0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
-       {0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
+       {0x0000a518, 0x1700002b, 0x1700002b, 0x1700002b, 0x1700002b, 0x1600002b, 0x1600002b, 0x1700000e, 0x1700000e},
+       {0x0000a51c, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1a00002d, 0x1a00002d, 0x1b000064, 0x1b000064},
+       {0x0000a520, 0x20000031, 0x20000031, 0x1f000031, 0x1f000031, 0x1e000031, 0x1e000031, 0x1f000242, 0x1f000242},
+       {0x0000a524, 0x24000051, 0x24000051, 0x23000051, 0x23000051, 0x23000051, 0x23000051, 0x23000229, 0x23000229},
+       {0x0000a528, 0x27000071, 0x27000071, 0x27000071, 0x27000071, 0x26000071, 0x26000071, 0x270002a2, 0x270002a2},
+       {0x0000a52c, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2c001203, 0x2c001203},
+       {0x0000a530, 0x3000028c, 0x3000028c, 0x2f00028c, 0x2f00028c, 0x2e00028c, 0x2e00028c, 0x30001803, 0x30001803},
+       {0x0000a534, 0x34000290, 0x34000290, 0x33000290, 0x33000290, 0x32000290, 0x32000290, 0x33000881, 0x33000881},
+       {0x0000a538, 0x37000292, 0x37000292, 0x36000292, 0x36000292, 0x35000292, 0x35000292, 0x38001809, 0x38001809},
+       {0x0000a53c, 0x3b02028d, 0x3b02028d, 0x3a02028d, 0x3a02028d, 0x3902028d, 0x3902028d, 0x3a000814, 0x3a000814},
+       {0x0000a540, 0x3f020291, 0x3f020291, 0x3e020291, 0x3e020291, 0x3d020291, 0x3d020291, 0x3f001a0c, 0x3f001a0c},
+       {0x0000a544, 0x44020490, 0x44020490, 0x43020490, 0x43020490, 0x42020490, 0x42020490, 0x43001a0e, 0x43001a0e},
+       {0x0000a548, 0x48020492, 0x48020492, 0x47020492, 0x47020492, 0x46020492, 0x46020492, 0x46001812, 0x46001812},
+       {0x0000a54c, 0x4c020692, 0x4c020692, 0x4b020692, 0x4b020692, 0x4a020692, 0x4a020692, 0x49001884, 0x49001884},
+       {0x0000a550, 0x50020892, 0x50020892, 0x4f020892, 0x4f020892, 0x4e020892, 0x4e020892, 0x4d001e84, 0x4d001e84},
+       {0x0000a554, 0x53040891, 0x53040891, 0x53040891, 0x53040891, 0x52040891, 0x52040891, 0x50001e69, 0x50001e69},
+       {0x0000a558, 0x58040893, 0x58040893, 0x57040893, 0x57040893, 0x56040893, 0x56040893, 0x550006f4, 0x550006f4},
+       {0x0000a55c, 0x5c0408b4, 0x5c0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x59000ad3, 0x59000ad3},
+       {0x0000a560, 0x610408b6, 0x610408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e000ad5, 0x5e000ad5},
+       {0x0000a564, 0x670408f6, 0x670408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x61001ced, 0x61001ced},
+       {0x0000a568, 0x6a040cf6, 0x6a040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x660018d4, 0x660018d4},
+       {0x0000a56c, 0x6d040d76, 0x6d040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x660018d4, 0x660018d4},
+       {0x0000a570, 0x70060db6, 0x70060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x660018d4, 0x660018d4},
+       {0x0000a574, 0x730a0df6, 0x730a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x660018d4, 0x660018d4},
+       {0x0000a578, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
+       {0x0000a57c, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
        {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000},
-       {0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02},
-       {0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04},
-       {0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000},
-       {0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000},
-       {0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000},
-       {0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000},
-       {0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05},
-       {0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06},
-       {0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07},
-       {0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07},
-       {0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07},
-       {0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07},
-       {0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
-       {0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
-       {0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+       {0x0000a60c, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x03804000, 0x03804000},
+       {0x0000a610, 0x04008b01, 0x04008b01, 0x04008b01, 0x04008b01, 0x03c08b01, 0x03c08b01, 0x0300ca02, 0x0300ca02},
+       {0x0000a614, 0x05811403, 0x05811403, 0x05411303, 0x05411303, 0x05411303, 0x05411303, 0x00000e04, 0x00000e04},
+       {0x0000a618, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
+       {0x0000a61c, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
+       {0x0000a620, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
+       {0x0000a624, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
+       {0x0000a628, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03804c05, 0x03804c05},
+       {0x0000a62c, 0x06815604, 0x06815604, 0x06415504, 0x06415504, 0x06015504, 0x06015504, 0x0701de06, 0x0701de06},
+       {0x0000a630, 0x07819a05, 0x07819a05, 0x07419905, 0x07419905, 0x07019805, 0x07019805, 0x07819c07, 0x07819c07},
+       {0x0000a634, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+       {0x0000a638, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+       {0x0000a63c, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+       {0x0000b2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+       {0x0000b2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+       {0x0000b2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
        {0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
-       {0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
-       {0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
-       {0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+       {0x0000c2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+       {0x0000c2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+       {0x0000c2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
        {0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
        {0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
-       {0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+       {0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
        {0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84},
        {0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
-       {0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+       {0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
        {0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
-       {0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+       {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
 };
 
 static const u32 ar955x_1p0_mac_core[][2] = {
@@ -846,7 +846,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = {
        {0x0000a44c, 0x00000001},
        {0x0000a450, 0x00010000},
        {0x0000a458, 0x00000000},
-       {0x0000a644, 0x3fad9d74},
+       {0x0000a644, 0xbfad9d74},
        {0x0000a648, 0x0048060a},
        {0x0000a64c, 0x00003c37},
        {0x0000a670, 0x03020100},
@@ -1277,7 +1277,7 @@ static const u32 ar955x_1p0_modes_fast_clock[][3] = {
        {0x0000801c, 0x148ec02b, 0x148ec057},
        {0x00008318, 0x000044c0, 0x00008980},
        {0x00009e00, 0x0372131c, 0x0372131c},
-       {0x0000a230, 0x0000000b, 0x00000016},
+       {0x0000a230, 0x0000400b, 0x00004016},
        {0x0000a254, 0x00000898, 0x00001130},
 };
 
index 6e1915aee712c5978d2d581311366e82b0d24d70..28fd99203f6447e4d3545b0fd12b920733ffc10c 100644 (file)
@@ -685,6 +685,82 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {
 
 #define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
 
+#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
+
+static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+       {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+       {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+       {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+       {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+       {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+       {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+       {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+       {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+       {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+       {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+       {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+       {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+       {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+       {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
+       {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
+       {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+       {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+       {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+       {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+       {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+       {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
 static const u32 ar9580_1p0_soc_preamble[][2] = {
        /* Addr      allmodes  */
        {0x000040a4, 0x00a0c1c9},
index 42794c546a4068ac91b47c1252153b9040362555..b2d6c18d1678961a9efe838f43ed1bffb3216a23 100644 (file)
@@ -109,14 +109,11 @@ struct ath_descdma {
        void *dd_desc;
        dma_addr_t dd_desc_paddr;
        u32 dd_desc_len;
-       struct ath_buf *dd_bufptr;
 };
 
 int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                      struct list_head *head, const char *name,
                      int nbuf, int ndesc, bool is_tx);
-void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
-                        struct list_head *head);
 
 /***********/
 /* RX / TX */
@@ -319,7 +316,6 @@ struct ath_rx {
        unsigned int rxfilter;
        struct list_head rxbuf;
        struct ath_descdma rxdma;
-       struct ath_buf *rx_bufptr;
        struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
 
        struct sk_buff *frag;
@@ -336,14 +332,12 @@ void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq);
 void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
 void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
 void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
-bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
-void ath_draintxq(struct ath_softc *sc,
-                    struct ath_txq *txq, bool retry_tx);
+bool ath_drain_all_txq(struct ath_softc *sc);
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
 void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
 int ath_tx_init(struct ath_softc *sc, int nbufs);
-void ath_tx_cleanup(struct ath_softc *sc);
 int ath_txq_update(struct ath_softc *sc, int qnum,
                   struct ath9k_tx_queue_info *q);
 void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
@@ -672,6 +666,23 @@ struct ath9k_vif_iter_data {
        int nadhocs;   /* number of adhoc vifs */
 };
 
+/* enum spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ *     something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ *     is performed manually.
+ * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
+ *     during a channel scan.
+ */
+enum spectral_mode {
+       SPECTRAL_DISABLED = 0,
+       SPECTRAL_BACKGROUND,
+       SPECTRAL_MANUAL,
+       SPECTRAL_CHANSCAN,
+};
+
 struct ath_softc {
        struct ieee80211_hw *hw;
        struct device *dev;
@@ -740,6 +751,10 @@ struct ath_softc {
        u8 ant_tx, ant_rx;
        struct dfs_pattern_detector *dfs_detector;
        u32 wow_enabled;
+       /* relay(fs) channel for spectral scan */
+       struct rchan *rfs_chan_spec_scan;
+       enum spectral_mode spectral_mode;
+       int scanning;
 
 #ifdef CONFIG_PM_SLEEP
        atomic_t wow_got_bmiss_intr;
@@ -748,6 +763,133 @@ struct ath_softc {
 #endif
 };
 
+#define SPECTRAL_SCAN_BITMASK          0x10
+/* Radar info packet format, used for DFS and spectral formats. */
+struct ath_radar_info {
+       u8 pulse_length_pri;
+       u8 pulse_length_ext;
+       u8 pulse_bw_info;
+} __packed;
+
+/* The HT20 spectral data has 4 bytes of additional information at it's end.
+ *
+ * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: all bins  max_magnitude[9:2]
+ * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_mag_info {
+       u8 all_bins[3];
+       u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_NUM_BINS         56
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data by -1/+2. This struct is for reference only.
+ */
+struct ath_ht20_fft_packet {
+       u8 data[SPECTRAL_HT20_NUM_BINS];
+       struct ath_ht20_mag_info mag_info;
+       struct ath_radar_info radar_info;
+} __packed;
+
+#define SPECTRAL_HT20_TOTAL_DATA_LEN   (sizeof(struct ath_ht20_fft_packet))
+
+/* Dynamic 20/40 mode:
+ *
+ * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: lower bins  max_magnitude[9:2]
+ * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
+ * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: upper bins  max_magnitude[9:2]
+ * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_40_mag_info {
+       u8 lower_bins[3];
+       u8 upper_bins[3];
+       u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_40_NUM_BINS              128
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data. This struct is for reference only.
+ */
+struct ath_ht20_40_fft_packet {
+       u8 data[SPECTRAL_HT20_40_NUM_BINS];
+       struct ath_ht20_40_mag_info mag_info;
+       struct ath_radar_info radar_info;
+} __packed;
+
+
+#define SPECTRAL_HT20_40_TOTAL_DATA_LEN        (sizeof(struct ath_ht20_40_fft_packet))
+
+/* grabs the max magnitude from the all/upper/lower bins */
+static inline u16 spectral_max_magnitude(u8 *bins)
+{
+       return (bins[0] & 0xc0) >> 6 |
+              (bins[1] & 0xff) << 2 |
+              (bins[2] & 0x03) << 10;
+}
+
+/* return the max magnitude from the all/upper/lower bins */
+static inline u8 spectral_max_index(u8 *bins)
+{
+       s8 m = (bins[2] & 0xfc) >> 2;
+
+       /* TODO: this still doesn't always report the right values ... */
+       if (m > 32)
+               m |= 0xe0;
+       else
+               m &= ~0xe0;
+
+       return m + 29;
+}
+
+/* return the bitmap weight from the all/upper/lower bins */
+static inline u8 spectral_bitmap_weight(u8 *bins)
+{
+       return bins[0] & 0x3f;
+}
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+       ATH_FFT_SAMPLE_HT20 = 0,
+};
+
+struct fft_sample_tlv {
+       u8 type;        /* see ath_fft_sample */
+       u16 length;
+       /* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+       struct fft_sample_tlv tlv;
+
+       u8 __alignment;
+
+       u16 freq;
+       s8 rssi;
+       s8 noise;
+
+       u16 max_magnitude;
+       u8 max_index;
+       u8 bitmap_weight;
+
+       u64 tsf;
+
+       u16 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
 void ath9k_tasklet(unsigned long data);
 int ath_cabq_update(struct ath_softc *);
 
@@ -770,6 +912,10 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath9k_reload_chainmask_settings(struct ath_softc *sc);
 
 bool ath9k_uses_beacons(int type);
+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+                              enum spectral_mode spectral_mode);
+
 
 #ifdef CONFIG_ATH9K_PCI
 int ath_pci_init(void);
index 2ca355e94da65467e36595990423c80be1b897b6..dd3771954bd7ce855c028aef8aa56f0f27134bcd 100644 (file)
@@ -199,7 +199,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
                if (sc->nvifs > 1) {
                        ath_dbg(common, BEACON,
                                "Flushing previous cabq traffic\n");
-                       ath_draintxq(sc, cabq, false);
+                       ath_draintxq(sc, cabq);
                }
        }
 
index e585fc827c50b2e9d5ff2fe08afb15cd49cedba6..6c5d313ebcb7eda614d350a718faa518625f9adb 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
+#include <linux/relay.h>
 #include <asm/unaligned.h>
 
 #include "ath9k.h"
@@ -965,6 +966,112 @@ static const struct file_operations fops_recv = {
        .llseek = default_llseek,
 };
 
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char *mode = "";
+       unsigned int len;
+
+       switch (sc->spectral_mode) {
+       case SPECTRAL_DISABLED:
+               mode = "disable";
+               break;
+       case SPECTRAL_BACKGROUND:
+               mode = "background";
+               break;
+       case SPECTRAL_CHANSCAN:
+               mode = "chanscan";
+               break;
+       case SPECTRAL_MANUAL:
+               mode = "manual";
+               break;
+       }
+       len = strlen(mode);
+       return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+
+       if (strncmp("trigger", buf, 7) == 0) {
+               ath9k_spectral_scan_trigger(sc->hw);
+       } else if (strncmp("background", buf, 9) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
+               ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
+       } else if (strncmp("chanscan", buf, 8) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
+               ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
+       } else if (strncmp("manual", buf, 6) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
+               ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
+       } else if (strncmp("disable", buf, 7) == 0) {
+               ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
+               ath_dbg(common, CONFIG, "spectral scan: disabled\n");
+       } else {
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+       .read = read_file_spec_scan_ctl,
+       .write = write_file_spec_scan_ctl,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+                                             struct dentry *parent,
+                                             umode_t mode,
+                                             struct rchan_buf *buf,
+                                             int *is_global)
+{
+       struct dentry *buf_file;
+
+       buf_file = debugfs_create_file(filename, mode, parent, buf,
+                                      &relay_file_operations);
+       *is_global = 1;
+       return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+       debugfs_remove(dentry);
+
+       return 0;
+}
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+                              struct fft_sample_tlv *fft_sample_tlv)
+{
+       if (!sc->rfs_chan_spec_scan)
+               return;
+
+       relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv,
+                   fft_sample_tlv->length + sizeof(*fft_sample_tlv));
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+       .create_buf_file = create_buf_file_handler,
+       .remove_buf_file = remove_buf_file_handler,
+};
+
+
 static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
                                 size_t count, loff_t *ppos)
 {
@@ -1779,6 +1886,14 @@ int ath9k_init_debug(struct ath_hw *ah)
                            &fops_base_eeprom);
        debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_modal_eeprom);
+       sc->rfs_chan_spec_scan = relay_open("spectral_scan",
+                                           sc->debug.debugfs_phy,
+                                           262144, 4, &rfs_spec_scan_cb,
+                                           NULL);
+       debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_spec_scan_ctl);
+
 #ifdef CONFIG_ATH9K_MAC_DEBUG
        debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_samps);
index 6df2ab62dcb706df5bef4a8afdf04593651f111a..a22c0d7807008f7b67b84b05b445105b276922e1 100644 (file)
@@ -23,6 +23,7 @@
 
 struct ath_txq;
 struct ath_buf;
+struct fft_sample_tlv;
 
 #ifdef CONFIG_ATH9K_DEBUGFS
 #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
@@ -321,6 +322,10 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
                              struct ieee80211_sta *sta,
                              struct dentry *dir);
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+                              struct fft_sample_tlv *fft_sample);
+
 #else
 
 #define RX_STAT_INC(c) /* NOP */
index 05d5ba66cac3588f64e8f6ab0545af76fbf88cbb..716058b675571b32c6693656dafeb567868b25cb 100644 (file)
@@ -280,14 +280,14 @@ err:
        return ret;
 }
 
-static int ath9k_reg_notifier(struct wiphy *wiphy,
-                             struct regulatory_request *request)
+static void ath9k_reg_notifier(struct wiphy *wiphy,
+                              struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct ath9k_htc_priv *priv = hw->priv;
 
-       return ath_reg_notifier_apply(wiphy, request,
-                                     ath9k_hw_regulatory(priv->ah));
+       ath_reg_notifier_apply(wiphy, request,
+                              ath9k_hw_regulatory(priv->ah));
 }
 
 static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
@@ -783,7 +783,7 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
        priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
        priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
 
-       snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
+       snprintf(hw->wiphy->fw_version, sizeof(hw->wiphy->fw_version), "%d.%d",
                 priv->fw_version_major,
                 priv->fw_version_minor);
 
index 9c07a8fa5134bb4611b93b9645c20fd0e0c414e3..a8016d70088aa3d492d15ff76f6f16f8f3c2df2f 100644 (file)
@@ -1628,7 +1628,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
                if (!ret)
                        ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
index 0f2b97f6b7390e32a920e0d645449e820d9d195a..14b701140b49aa3b66c4eb1a280d51500a69f2db 100644 (file)
@@ -101,22 +101,6 @@ static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah,
        ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan);
 }
 
-static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
-{
-       if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks)
-               return 0;
-
-       return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah);
-}
-
-static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
-{
-       if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks)
-               return;
-
-       ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah);
-}
-
 static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
                                        struct ath9k_channel *chan,
                                        u16 modesIndex)
index 7cb787065913f7ee118909c2b372a8e07651f38c..42cf3c7f1e25bd29b23ec1c64dad10339b4d2416 100644 (file)
@@ -54,11 +54,6 @@ static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
        ath9k_hw_private_ops(ah)->init_cal_settings(ah);
 }
 
-static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
-{
-       ath9k_hw_private_ops(ah)->init_mode_regs(ah);
-}
-
 static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
                                        struct ath9k_channel *chan)
 {
@@ -208,7 +203,7 @@ void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
        udelay(hw_delay + BASE_ACTIVATE_DELAY);
 }
 
-void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
                          int column, unsigned int *writecnt)
 {
        int r;
@@ -554,28 +549,19 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
                ah->eep_ops->get_eeprom_ver(ah),
                ah->eep_ops->get_eeprom_rev(ah));
 
-       ecode = ath9k_hw_rf_alloc_ext_banks(ah);
-       if (ecode) {
-               ath_err(ath9k_hw_common(ah),
-                       "Failed allocating banks for external radio\n");
-               ath9k_hw_rf_free_ext_banks(ah);
-               return ecode;
-       }
-
-       if (ah->config.enable_ani) {
-               ath9k_hw_ani_setup(ah);
+       if (ah->config.enable_ani)
                ath9k_hw_ani_init(ah);
-       }
 
        return 0;
 }
 
-static void ath9k_hw_attach_ops(struct ath_hw *ah)
+static int ath9k_hw_attach_ops(struct ath_hw *ah)
 {
-       if (AR_SREV_9300_20_OR_LATER(ah))
-               ar9003_hw_attach_ops(ah);
-       else
-               ar9002_hw_attach_ops(ah);
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               return ar9002_hw_attach_ops(ah);
+
+       ar9003_hw_attach_ops(ah);
+       return 0;
 }
 
 /* Called for all hardware families */
@@ -611,7 +597,9 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        ath9k_hw_init_defaults(ah);
        ath9k_hw_init_config(ah);
 
-       ath9k_hw_attach_ops(ah);
+       r = ath9k_hw_attach_ops(ah);
+       if (r)
+               return r;
 
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
                ath_err(common, "Couldn't wakeup chip\n");
@@ -675,8 +663,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        if (!AR_SREV_9300_20_OR_LATER(ah))
                ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
 
-       ath9k_hw_init_mode_regs(ah);
-
        if (!ah->is_pciexpress)
                ath9k_hw_disablepcie(ah);
 
@@ -1153,12 +1139,9 @@ void ath9k_hw_deinit(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
 
        if (common->state < ATH_HW_INITIALIZED)
-               goto free_hw;
+               return;
 
        ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
-
-free_hw:
-       ath9k_hw_rf_free_ext_banks(ah);
 }
 EXPORT_SYMBOL(ath9k_hw_deinit);
 
@@ -2576,12 +2559,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                rx_chainmask >>= 1;
        }
 
-       if (AR_SREV_9300_20_OR_LATER(ah)) {
-               ah->enabled_cals |= TX_IQ_CAL;
-               if (AR_SREV_9485_OR_LATER(ah))
-                       ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
-       }
-
        if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
                if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE))
                        pCap->hw_caps |= ATH9K_HW_CAP_MCI;
@@ -2590,7 +2567,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        pCap->hw_caps |= ATH9K_HW_CAP_RTT;
        }
 
-
        if (AR_SREV_9280_20_OR_LATER(ah)) {
                pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE |
                                 ATH9K_HW_WOW_PATTERN_MATCH_EXACT;
index 9d26fc56ca56a6bf7d4e8ac0ed91366df0de50cd..784e81ccb9031ed6dd3d2f29ad1dcda0faa9f4f7 100644 (file)
@@ -397,6 +397,7 @@ enum ath9k_int {
 #define MAX_RTT_TABLE_ENTRY     6
 #define MAX_IQCAL_MEASUREMENT  8
 #define MAX_CL_TAB_ENTRY       16
+#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
 
 struct ath9k_hw_cal_data {
        u16 channel;
@@ -599,13 +600,10 @@ struct ath_hw_radar_conf {
  * @init_cal_settings: setup types of calibrations supported
  * @init_cal: starts actual calibration
  *
- * @init_mode_regs: Initializes mode registers
  * @init_mode_gain_regs: Initialize TX/RX gain registers
  *
  * @rf_set_freq: change frequency
  * @spur_mitigate_freq: spur mitigation
- * @rf_alloc_ext_banks:
- * @rf_free_ext_banks:
  * @set_rf_regs:
  * @compute_pll_control: compute the PLL control value to use for
  *     AR_RTC_PLL_CONTROL for a given channel
@@ -620,7 +618,6 @@ struct ath_hw_private_ops {
        void (*init_cal_settings)(struct ath_hw *ah);
        bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
 
-       void (*init_mode_regs)(struct ath_hw *ah);
        void (*init_mode_gain_regs)(struct ath_hw *ah);
        void (*setup_calibration)(struct ath_hw *ah,
                                  struct ath9k_cal_list *currCal);
@@ -630,8 +627,6 @@ struct ath_hw_private_ops {
                           struct ath9k_channel *chan);
        void (*spur_mitigate_freq)(struct ath_hw *ah,
                                   struct ath9k_channel *chan);
-       int (*rf_alloc_ext_banks)(struct ath_hw *ah);
-       void (*rf_free_ext_banks)(struct ath_hw *ah);
        bool (*set_rf_regs)(struct ath_hw *ah,
                            struct ath9k_channel *chan,
                            u16 modesIndex);
@@ -660,6 +655,37 @@ struct ath_hw_private_ops {
        void (*ani_cache_ini_regs)(struct ath_hw *ah);
 };
 
+/**
+ * struct ath_spec_scan - parameters for Atheros spectral scan
+ *
+ * @enabled: enable/disable spectral scan
+ * @short_repeat: controls whether the chip is in spectral scan mode
+ *               for 4 usec (enabled) or 204 usec (disabled)
+ * @count: number of scan results requested. There are special meanings
+ *        in some chip revisions:
+ *        AR92xx: highest bit set (>=128) for endless mode
+ *                (spectral scan won't stopped until explicitly disabled)
+ *        AR9300 and newer: 0 for endless mode
+ * @endless: true if endless mode is intended. Otherwise, count value is
+ *           corrected to the next possible value.
+ * @period: time duration between successive spectral scan entry points
+ *         (period*256*Tclk). Tclk = ath_common->clockrate
+ * @fft_period: PHY passes FFT frames to MAC every (fft_period+1)*4uS
+ *
+ * Note: Tclk = 40MHz or 44MHz depending upon operating mode.
+ *      Typically it's 44MHz in 2/5GHz on later chips, but there's
+ *      a "fast clock" check for this in 5GHz.
+ *
+ */
+struct ath_spec_scan {
+       bool enabled;
+       bool short_repeat;
+       bool endless;
+       u8 count;
+       u8 period;
+       u8 fft_period;
+};
+
 /**
  * struct ath_hw_ops - callbacks used by hardware code and driver code
  *
@@ -668,6 +694,10 @@ struct ath_hw_private_ops {
  *
  * @config_pci_powersave:
  * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ *
+ * @spectral_scan_config: set parameters for spectral scan and enable/disable it
+ * @spectral_scan_trigger: trigger a spectral scan run
+ * @spectral_scan_wait: wait for a spectral scan run to finish
  */
 struct ath_hw_ops {
        void (*config_pci_powersave)(struct ath_hw *ah,
@@ -688,6 +718,10 @@ struct ath_hw_ops {
        void (*antdiv_comb_conf_set)(struct ath_hw *ah,
                        struct ath_hw_antcomb_conf *antconf);
        void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
+       void (*spectral_scan_config)(struct ath_hw *ah,
+                                    struct ath_spec_scan *param);
+       void (*spectral_scan_trigger)(struct ath_hw *ah);
+       void (*spectral_scan_wait)(struct ath_hw *ah);
 };
 
 struct ath_nf_limits {
@@ -710,6 +744,7 @@ enum ath_cal_list {
 struct ath_hw {
        struct ath_ops reg_ops;
 
+       struct device *dev;
        struct ieee80211_hw *hw;
        struct ath_common common;
        struct ath9k_hw_version hw_version;
@@ -771,7 +806,6 @@ struct ath_hw {
        struct ath9k_cal_list iq_caldata;
        struct ath9k_cal_list adcgain_caldata;
        struct ath9k_cal_list adcdc_caldata;
-       struct ath9k_cal_list tempCompCalData;
        struct ath9k_cal_list *cal_list;
        struct ath9k_cal_list *cal_list_last;
        struct ath9k_cal_list *cal_list_curr;
@@ -830,10 +864,6 @@ struct ath_hw {
        /* ANI */
        u32 proc_phyerr;
        u32 aniperiod;
-       int totalSizeDesired[5];
-       int coarse_high[5];
-       int coarse_low[5];
-       int firpwr[5];
        enum ath9k_ani_cmd ani_function;
        u32 ani_skip_count;
 
@@ -979,7 +1009,7 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
 void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
                          int hw_delay);
 bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
-void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
                          int column, unsigned int *writecnt);
 u32 ath9k_hw_reverse_bits(u32 val, u32 n);
 u16 ath9k_hw_computetxtime(struct ath_hw *ah,
@@ -1069,14 +1099,14 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah);
 void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
 
 /* Hardware family op attach helpers */
-void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
+int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
 void ar9002_hw_attach_phy_ops(struct ath_hw *ah);
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah);
 
 void ar9002_hw_attach_calib_ops(struct ath_hw *ah);
 void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
 
-void ar9002_hw_attach_ops(struct ath_hw *ah);
+int ar9002_hw_attach_ops(struct ath_hw *ah);
 void ar9003_hw_attach_ops(struct ath_hw *ah);
 
 void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
index f69ef5d48c7b96119cb516259f41f2256f150747..4b1abc7da98c559fcda19845caa036c246d5b444 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/ath9k_platform.h>
 #include <linux/module.h>
+#include <linux/relay.h>
 
 #include "ath9k.h"
 
@@ -302,16 +303,15 @@ static void setup_ht_cap(struct ath_softc *sc,
        ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
 }
 
-static int ath9k_reg_notifier(struct wiphy *wiphy,
-                             struct regulatory_request *request)
+static void ath9k_reg_notifier(struct wiphy *wiphy,
+                              struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
-       int ret;
 
-       ret = ath_reg_notifier_apply(wiphy, request, reg);
+       ath_reg_notifier_apply(wiphy, request, reg);
 
        /* Set tx power */
        if (ah->curchan) {
@@ -321,8 +321,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
                sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
                ath9k_ps_restore(sc);
        }
-
-       return ret;
 }
 
 /*
@@ -337,7 +335,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        u8 *ds;
        struct ath_buf *bf;
-       int i, bsize, error, desc_len;
+       int i, bsize, desc_len;
 
        ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n",
                name, nbuf, ndesc);
@@ -353,8 +351,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
        if ((desc_len % 4) != 0) {
                ath_err(common, "ath_desc not DWORD aligned\n");
                BUG_ON((desc_len % 4) != 0);
-               error = -ENOMEM;
-               goto fail;
+               return -ENOMEM;
        }
 
        dd->dd_desc_len = desc_len * nbuf * ndesc;
@@ -378,12 +375,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
        }
 
        /* allocate descriptors */
-       dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
-                                        &dd->dd_desc_paddr, GFP_KERNEL);
-       if (dd->dd_desc == NULL) {
-               error = -ENOMEM;
-               goto fail;
-       }
+       dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
+                                         &dd->dd_desc_paddr, GFP_KERNEL);
+       if (!dd->dd_desc)
+               return -ENOMEM;
+
        ds = (u8 *) dd->dd_desc;
        ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
                name, ds, (u32) dd->dd_desc_len,
@@ -391,12 +387,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 
        /* allocate buffers */
        bsize = sizeof(struct ath_buf) * nbuf;
-       bf = kzalloc(bsize, GFP_KERNEL);
-       if (bf == NULL) {
-               error = -ENOMEM;
-               goto fail2;
-       }
-       dd->dd_bufptr = bf;
+       bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
+       if (!bf)
+               return -ENOMEM;
 
        for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
                bf->bf_desc = ds;
@@ -422,12 +415,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                list_add_tail(&bf->list, head);
        }
        return 0;
-fail2:
-       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-                         dd->dd_desc_paddr);
-fail:
-       memset(dd, 0, sizeof(*dd));
-       return error;
 }
 
 static int ath9k_init_queues(struct ath_softc *sc)
@@ -457,11 +444,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc)
                     ATH9K_NUM_CHANNELS);
 
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
-               channels = kmemdup(ath9k_2ghz_chantable,
+               channels = devm_kzalloc(sc->dev,
                        sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
                if (!channels)
                    return -ENOMEM;
 
+               memcpy(channels, ath9k_2ghz_chantable,
+                      sizeof(ath9k_2ghz_chantable));
                sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
                sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
                sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
@@ -472,14 +461,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc)
        }
 
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
-               channels = kmemdup(ath9k_5ghz_chantable,
+               channels = devm_kzalloc(sc->dev,
                        sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
-               if (!channels) {
-                       if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
-                               kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
+               if (!channels)
                        return -ENOMEM;
-               }
 
+               memcpy(channels, ath9k_5ghz_chantable,
+                      sizeof(ath9k_5ghz_chantable));
                sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
                sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
                sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
@@ -565,10 +553,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        int ret = 0, i;
        int csz = 0;
 
-       ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+       ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL);
        if (!ah)
                return -ENOMEM;
 
+       ah->dev = sc->dev;
        ah->hw = sc->hw;
        ah->hw_version.devid = devid;
        ah->reg_ops.read = ath9k_ioread32;
@@ -636,7 +625,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        if (pdata && pdata->eeprom_name) {
                ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
                if (ret)
-                       goto err_eeprom;
+                       return ret;
        }
 
        /* Initializes the hardware for all supported chipsets */
@@ -676,10 +665,6 @@ err_queues:
        ath9k_hw_deinit(ah);
 err_hw:
        ath9k_eeprom_release(sc);
-err_eeprom:
-       kfree(ah);
-       sc->sc_ah = NULL;
-
        return ret;
 }
 
@@ -844,8 +829,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
 
        /* Bring up device */
        error = ath9k_init_softc(devid, sc, bus_ops);
-       if (error != 0)
-               goto error_init;
+       if (error)
+               return error;
 
        ah = sc->sc_ah;
        common = ath9k_hw_common(ah);
@@ -855,19 +840,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
        error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
                              ath9k_reg_notifier);
        if (error)
-               goto error_regd;
+               goto deinit;
 
        reg = &common->regulatory;
 
        /* Setup TX DMA */
        error = ath_tx_init(sc, ATH_TXBUF);
        if (error != 0)
-               goto error_tx;
+               goto deinit;
 
        /* Setup RX DMA */
        error = ath_rx_init(sc, ATH_RXBUF);
        if (error != 0)
-               goto error_rx;
+               goto deinit;
 
        ath9k_init_txpower_limits(sc);
 
@@ -881,19 +866,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
        /* Register with mac80211 */
        error = ieee80211_register_hw(hw);
        if (error)
-               goto error_register;
+               goto rx_cleanup;
 
        error = ath9k_init_debug(ah);
        if (error) {
                ath_err(common, "Unable to create debugfs files\n");
-               goto error_world;
+               goto unregister;
        }
 
        /* Handle world regulatory */
        if (!ath_is_world_regd(reg)) {
                error = regulatory_hint(hw->wiphy, reg->alpha2);
                if (error)
-                       goto error_world;
+                       goto unregister;
        }
 
        ath_init_leds(sc);
@@ -901,17 +886,12 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
 
        return 0;
 
-error_world:
+unregister:
        ieee80211_unregister_hw(hw);
-error_register:
+rx_cleanup:
        ath_rx_cleanup(sc);
-error_rx:
-       ath_tx_cleanup(sc);
-error_tx:
-       /* Nothing */
-error_regd:
+deinit:
        ath9k_deinit_softc(sc);
-error_init:
        return error;
 }
 
@@ -923,12 +903,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 {
        int i = 0;
 
-       if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
-               kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
-
-       if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
-               kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
-
        ath9k_deinit_btcoex(sc);
 
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
@@ -940,8 +914,11 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
                sc->dfs_detector->exit(sc->dfs_detector);
 
        ath9k_eeprom_release(sc);
-       kfree(sc->sc_ah);
-       sc->sc_ah = NULL;
+
+       if (sc->rfs_chan_spec_scan) {
+               relay_close(sc->rfs_chan_spec_scan);
+               sc->rfs_chan_spec_scan = NULL;
+       }
 }
 
 void ath9k_deinit_device(struct ath_softc *sc)
@@ -957,22 +934,9 @@ void ath9k_deinit_device(struct ath_softc *sc)
 
        ieee80211_unregister_hw(hw);
        ath_rx_cleanup(sc);
-       ath_tx_cleanup(sc);
        ath9k_deinit_softc(sc);
 }
 
-void ath_descdma_cleanup(struct ath_softc *sc,
-                        struct ath_descdma *dd,
-                        struct list_head *head)
-{
-       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-                         dd->dd_desc_paddr);
-
-       INIT_LIST_HEAD(head);
-       kfree(dd->dd_bufptr);
-       memset(dd, 0, sizeof(*dd));
-}
-
 /************************/
 /*     Module Hooks     */
 /************************/
index 4a745e68dd941d9351e4fe911b47d76ec288551d..1ff817061ebc44e07d1af87edb4d9ce471980bb2 100644 (file)
@@ -226,7 +226,8 @@ enum ath9k_phyerr {
        ATH9K_PHYERR_HT_LENGTH_ILLEGAL    = 35,
        ATH9K_PHYERR_HT_RATE_ILLEGAL      = 36,
 
-       ATH9K_PHYERR_MAX                  = 37,
+       ATH9K_PHYERR_SPECTRAL             = 38,
+       ATH9K_PHYERR_MAX                  = 39,
 };
 
 struct ath_desc {
index dd91f8fdc01c3ea44c922bbbbd14bee2df4fd6db..4b72b660f1800d25d9416668649260996afc411a 100644 (file)
@@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc)
        ath_start_ani(sc);
 }
 
-static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
+static bool ath_prepare_reset(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        bool ret = true;
@@ -196,10 +196,10 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
        ath9k_debug_samp_bb_mac(sc);
        ath9k_hw_disable_interrupts(ah);
 
-       if (!ath_stoprecv(sc))
+       if (!ath_drain_all_txq(sc))
                ret = false;
 
-       if (!ath_drain_all_txq(sc, retry_tx))
+       if (!ath_stoprecv(sc))
                ret = false;
 
        return ret;
@@ -247,8 +247,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
        return true;
 }
 
-static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
-                             bool retry_tx)
+static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -271,7 +270,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
                hchan = ah->curchan;
        }
 
-       if (!ath_prepare_reset(sc, retry_tx))
+       if (!ath_prepare_reset(sc))
                fastcc = false;
 
        ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
@@ -312,7 +311,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
        if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return -EIO;
 
-       r = ath_reset_internal(sc, hchan, false);
+       r = ath_reset_internal(sc, hchan);
 
        return r;
 }
@@ -542,23 +541,21 @@ chip_reset:
 #undef SCHED_INTR
 }
 
-static int ath_reset(struct ath_softc *sc, bool retry_tx)
+static int ath_reset(struct ath_softc *sc)
 {
-       int r;
+       int i, r;
 
        ath9k_ps_wakeup(sc);
 
-       r = ath_reset_internal(sc, NULL, retry_tx);
+       r = ath_reset_internal(sc, NULL);
 
-       if (retry_tx) {
-               int i;
-               for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-                       if (ATH_TXQ_SETUP(sc, i)) {
-                               spin_lock_bh(&sc->tx.txq[i].axq_lock);
-                               ath_txq_schedule(sc, &sc->tx.txq[i]);
-                               spin_unlock_bh(&sc->tx.txq[i].axq_lock);
-                       }
-               }
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+               if (!ATH_TXQ_SETUP(sc, i))
+                       continue;
+
+               spin_lock_bh(&sc->tx.txq[i].axq_lock);
+               ath_txq_schedule(sc, &sc->tx.txq[i]);
+               spin_unlock_bh(&sc->tx.txq[i].axq_lock);
        }
 
        ath9k_ps_restore(sc);
@@ -579,7 +576,7 @@ void ath_reset_work(struct work_struct *work)
 {
        struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
 
-       ath_reset(sc, true);
+       ath_reset(sc);
 }
 
 /**********************/
@@ -797,7 +794,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
                ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
        }
 
-       ath_prepare_reset(sc, false);
+       ath_prepare_reset(sc);
 
        if (sc->rx.frag) {
                dev_kfree_skb_any(sc->rx.frag);
@@ -1068,6 +1065,86 @@ static void ath9k_disable_ps(struct ath_softc *sc)
        ath_dbg(common, PS, "PowerSave disabled\n");
 }
 
+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 rxfilter;
+
+       if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+               ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+               return;
+       }
+
+       ath9k_ps_wakeup(sc);
+       rxfilter = ath9k_hw_getrxfilter(ah);
+       ath9k_hw_setrxfilter(ah, rxfilter |
+                                ATH9K_RX_FILTER_PHYRADAR |
+                                ATH9K_RX_FILTER_PHYERR);
+
+       /* TODO: usually this should not be neccesary, but for some reason
+        * (or in some mode?) the trigger must be called after the
+        * configuration, otherwise the register will have its values reset
+        * (on my ar9220 to value 0x01002310)
+        */
+       ath9k_spectral_scan_config(hw, sc->spectral_mode);
+       ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
+       ath9k_ps_restore(sc);
+}
+
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+                              enum spectral_mode spectral_mode)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_spec_scan param;
+
+       if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+               ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+               return -1;
+       }
+
+       /* NOTE: this will generate a few samples ...
+        *
+        * TODO: review default parameters, and/or define an interface to set
+        * them.
+        */
+       param.enabled = 1;
+       param.short_repeat = true;
+       param.count = 8;
+       param.endless = false;
+       param.period = 0xFF;
+       param.fft_period = 0xF;
+
+       switch (spectral_mode) {
+       case SPECTRAL_DISABLED:
+               param.enabled = 0;
+               break;
+       case SPECTRAL_BACKGROUND:
+               /* send endless samples.
+                * TODO: is this really useful for "background"?
+                */
+               param.endless = 1;
+               break;
+       case SPECTRAL_CHANSCAN:
+               break;
+       case SPECTRAL_MANUAL:
+               break;
+       default:
+               return -1;
+       }
+
+       ath9k_ps_wakeup(sc);
+       ath9k_hw_ops(ah)->spectral_scan_config(ah, &param);
+       ath9k_ps_restore(sc);
+
+       sc->spectral_mode = spectral_mode;
+
+       return 0;
+}
+
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ath_softc *sc = hw->priv;
@@ -1181,6 +1258,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                 */
                if (old_pos >= 0)
                        ath_update_survey_nf(sc, old_pos);
+
+               /* perform spectral scan if requested. */
+               if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
+                       ath9k_spectral_scan_trigger(hw);
+
        }
 
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -1603,7 +1685,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                        ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                ath9k_ps_restore(sc);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                ath9k_ps_wakeup(sc);
                ath_tx_aggr_stop(sc, sta, tid);
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -1722,11 +1806,11 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
        if (drop) {
                ath9k_ps_wakeup(sc);
                spin_lock_bh(&sc->sc_pcu_lock);
-               drain_txq = ath_drain_all_txq(sc, false);
+               drain_txq = ath_drain_all_txq(sc);
                spin_unlock_bh(&sc->sc_pcu_lock);
 
                if (!drain_txq)
-                       ath_reset(sc, false);
+                       ath_reset(sc);
 
                ath9k_ps_restore(sc);
                ieee80211_wake_queues(hw);
@@ -2234,6 +2318,19 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
 }
 
 #endif
+static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
+{
+       struct ath_softc *sc = hw->priv;
+
+       sc->scanning = 1;
+}
+
+static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct ath_softc *sc = hw->priv;
+
+       sc->scanning = 0;
+}
 
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
@@ -2280,4 +2377,6 @@ struct ieee80211_ops ath9k_ops = {
        .sta_add_debugfs    = ath9k_sta_add_debugfs,
        .sta_remove_debugfs = ath9k_sta_remove_debugfs,
 #endif
+       .sw_scan_start      = ath9k_sw_scan_start,
+       .sw_scan_complete   = ath9k_sw_scan_complete,
 };
index 5c02702f21e7e1d3508b493ca89499b0226ce2c4..d2074334ec9b9c228c500df79fcc760066b1b669 100644 (file)
@@ -438,7 +438,7 @@ int ath_mci_setup(struct ath_softc *sc)
        struct ath_mci_buf *buf = &mci->sched_buf;
        int ret;
 
-       buf->bf_addr = dma_alloc_coherent(sc->dev,
+       buf->bf_addr = dmam_alloc_coherent(sc->dev,
                                  ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
                                  &buf->bf_paddr, GFP_KERNEL);
 
@@ -477,11 +477,6 @@ void ath_mci_cleanup(struct ath_softc *sc)
        struct ath_mci_coex *mci = &sc->mci_coex;
        struct ath_mci_buf *buf = &mci->sched_buf;
 
-       if (buf->bf_addr)
-               dma_free_coherent(sc->dev,
-                                 ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
-                                 buf->bf_addr, buf->bf_paddr);
-
        ar9003_mci_cleanup(ah);
 
        ath_dbg(common, MCI, "MCI De-Initialized\n");
index 7ae73fbd91361092f1a0590be0cbc2e2b0ecc9a4..0e0d39583837219a60a374d69494933b0ffc4e43 100644 (file)
@@ -147,7 +147,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
 
 static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       void __iomem *mem;
        struct ath_softc *sc;
        struct ieee80211_hw *hw;
        u8 csz;
@@ -155,19 +154,19 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        int ret = 0;
        char hw_name[64];
 
-       if (pci_enable_device(pdev))
+       if (pcim_enable_device(pdev))
                return -EIO;
 
        ret =  pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
        if (ret) {
                pr_err("32-bit DMA not available\n");
-               goto err_dma;
+               return ret;
        }
 
        ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
        if (ret) {
                pr_err("32-bit DMA consistent DMA enable failed\n");
-               goto err_dma;
+               return ret;
        }
 
        /*
@@ -203,25 +202,16 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if ((val & 0x0000ff00) != 0)
                pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
-       ret = pci_request_region(pdev, 0, "ath9k");
+       ret = pcim_iomap_regions(pdev, BIT(0), "ath9k");
        if (ret) {
                dev_err(&pdev->dev, "PCI memory region reserve error\n");
-               ret = -ENODEV;
-               goto err_region;
-       }
-
-       mem = pci_iomap(pdev, 0, 0);
-       if (!mem) {
-               pr_err("PCI memory map error\n") ;
-               ret = -EIO;
-               goto err_iomap;
+               return -ENODEV;
        }
 
        hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
        if (!hw) {
                dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
-               ret = -ENOMEM;
-               goto err_alloc_hw;
+               return -ENOMEM;
        }
 
        SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -230,7 +220,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        sc = hw->priv;
        sc->hw = hw;
        sc->dev = &pdev->dev;
-       sc->mem = mem;
+       sc->mem = pcim_iomap_table(pdev)[0];
 
        /* Will be cleared in ath9k_start() */
        set_bit(SC_OP_INVALID, &sc->sc_flags);
@@ -251,7 +241,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
        wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
-                  hw_name, (unsigned long)mem, pdev->irq);
+                  hw_name, (unsigned long)sc->mem, pdev->irq);
 
        return 0;
 
@@ -259,14 +249,6 @@ err_init:
        free_irq(sc->irq, sc);
 err_irq:
        ieee80211_free_hw(hw);
-err_alloc_hw:
-       pci_iounmap(pdev, mem);
-err_iomap:
-       pci_release_region(pdev, 0);
-err_region:
-       /* Nothing */
-err_dma:
-       pci_disable_device(pdev);
        return ret;
 }
 
@@ -274,17 +256,12 @@ static void ath_pci_remove(struct pci_dev *pdev)
 {
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath_softc *sc = hw->priv;
-       void __iomem *mem = sc->mem;
 
        if (!is_ath9k_unloaded)
                sc->sc_ah->ah_flags |= AH_UNPLUGGED;
        ath9k_deinit_device(sc);
        free_irq(sc->irq, sc);
        ieee80211_free_hw(sc->hw);
-
-       pci_iounmap(pdev, mem);
-       pci_disable_device(pdev);
-       pci_release_region(pdev, 0);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 90752f2469704bbbb2bf7cae86a1c2cb4029435a..d7c129bb571b56c958becf7e7eed1841406d8293 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/dma-mapping.h>
+#include <linux/relay.h>
 #include "ath9k.h"
 #include "ar9003_mac.h"
 
@@ -180,11 +181,6 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc)
                        bf->bf_mpdu = NULL;
                }
        }
-
-       INIT_LIST_HEAD(&sc->rx.rxbuf);
-
-       kfree(sc->rx.rx_bufptr);
-       sc->rx.rx_bufptr = NULL;
 }
 
 static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
@@ -211,12 +207,11 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
                               ah->caps.rx_hp_qdepth);
 
        size = sizeof(struct ath_buf) * nbufs;
-       bf = kzalloc(size, GFP_KERNEL);
+       bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);
        if (!bf)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&sc->rx.rxbuf);
-       sc->rx.rx_bufptr = bf;
 
        for (i = 0; i < nbufs; i++, bf++) {
                skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
@@ -357,9 +352,6 @@ void ath_rx_cleanup(struct ath_softc *sc)
                                bf->bf_mpdu = NULL;
                        }
                }
-
-               if (sc->rx.rxdma.dd_desc_len != 0)
-                       ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
        }
 }
 
@@ -1024,6 +1016,108 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
                rxs->flag &= ~RX_FLAG_DECRYPTED;
 }
 
+static s8 fix_rssi_inv_only(u8 rssi_val)
+{
+       if (rssi_val == 128)
+               rssi_val = 0;
+       return (s8) rssi_val;
+}
+
+
+static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
+                           struct ath_rx_status *rs, u64 tsf)
+{
+#ifdef CONFIG_ATH_DEBUG
+       struct ath_hw *ah = sc->sc_ah;
+       u8 bins[SPECTRAL_HT20_NUM_BINS];
+       u8 *vdata = (u8 *)hdr;
+       struct fft_sample_ht20 fft_sample;
+       struct ath_radar_info *radar_info;
+       struct ath_ht20_mag_info *mag_info;
+       int len = rs->rs_datalen;
+       int i, dc_pos;
+
+       /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
+        * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
+        * yet, but this is supposed to be possible as well.
+        */
+       if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
+           rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
+           rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
+               return;
+
+       /* Variation in the data length is possible and will be fixed later.
+        * Note that we only support HT20 for now.
+        *
+        * TODO: add HT20_40 support as well.
+        */
+       if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
+           (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
+               return;
+
+       /* check if spectral scan bit is set. This does not have to be checked
+        * if received through a SPECTRAL phy error, but shouldn't hurt.
+        */
+       radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
+       if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
+               return;
+
+       fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
+       fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
+
+       fft_sample.freq = ah->curchan->chan->center_freq;
+       fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
+       fft_sample.noise = ah->noise;
+
+       switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
+       case 0:
+               /* length correct, nothing to do. */
+               memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
+               break;
+       case -1:
+               /* first byte missing, duplicate it. */
+               memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
+               bins[0] = vdata[0];
+               break;
+       case 2:
+               /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
+               memcpy(bins, vdata, 30);
+               bins[30] = vdata[31];
+               memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
+               break;
+       case 1:
+               /* MAC added 2 extra bytes AND first byte is missing. */
+               bins[0] = vdata[0];
+               memcpy(&bins[0], vdata, 30);
+               bins[31] = vdata[31];
+               memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
+               break;
+       default:
+               return;
+       }
+
+       /* DC value (value in the middle) is the blind spot of the spectral
+        * sample and invalid, interpolate it.
+        */
+       dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+       bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
+
+       /* mag data is at the end of the frame, in front of radar_info */
+       mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
+
+       /* Apply exponent and grab further auxiliary information. */
+       for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++)
+               fft_sample.data[i] = bins[i] << mag_info->max_exp;
+
+       fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins);
+       fft_sample.max_index = spectral_max_index(mag_info->all_bins);
+       fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
+       fft_sample.tsf = tsf;
+
+       ath_debug_send_fft_sample(sc, &fft_sample.tlv);
+#endif
+}
+
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
        struct ath_buf *bf;
@@ -1108,6 +1202,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
                        rxs->mactime += 0x100000000ULL;
 
+               if ((rs.rs_status & ATH9K_RXERR_PHY))
+                       ath_process_fft(sc, hdr, &rs, rxs->mactime);
+
                retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
                                                 rxs, &decrypt_error);
                if (retval)
index ad3c82c091775a7011f7a0638da7522e15685c83..5929850649f0ee45a024a8328d6c76c17b5127bb 100644 (file)
 #define AR_SREV_REVISION_9271_11       1
 #define AR_SREV_VERSION_9300           0x1c0
 #define AR_SREV_REVISION_9300_20       2 /* 2.0 and 2.1 */
+#define AR_SREV_REVISION_9300_22       3
 #define AR_SREV_VERSION_9330           0x200
 #define AR_SREV_REVISION_9330_10       0
 #define AR_SREV_REVISION_9330_11       1
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
 #define AR_SREV_9300_20_OR_LATER(_ah) \
        ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
+#define AR_SREV_9300_22(_ah) \
+       (AR_SREV_9300(ah) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_22))
 
 #define AR_SREV_9330(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330))
 
 #define AR_SREV_9485(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
-#define AR_SREV_9485_10(_ah) \
-       (AR_SREV_9485(_ah) && \
-        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10))
 #define AR_SREV_9485_11(_ah) \
        (AR_SREV_9485(_ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
index 90e48a0fafe5a3ca6e12be66e6b0402bdf7feaf0..feacaafee959b358d60b8cc03f43f20c7e05c71c 100644 (file)
@@ -378,7 +378,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
 
 static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                                 struct ath_buf *bf, struct list_head *bf_q,
-                                struct ath_tx_status *ts, int txok, bool retry)
+                                struct ath_tx_status *ts, int txok)
 {
        struct ath_node *an = NULL;
        struct sk_buff *skb;
@@ -490,7 +490,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                } else if (!isaggr && txok) {
                        /* transmit completion */
                        acked_cnt++;
-               } else if ((tid->state & AGGR_CLEANUP) || !retry) {
+               } else if (tid->state & AGGR_CLEANUP) {
                        /*
                         * cleanup in progress, just fail
                         * the un-acked sub-frames
@@ -604,6 +604,37 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
 }
 
+static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
+{
+    struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
+    return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+}
+
+static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
+                                 struct ath_tx_status *ts, struct ath_buf *bf,
+                                 struct list_head *bf_head)
+{
+       bool txok, flush;
+
+       txok = !(ts->ts_status & ATH9K_TXERR_MASK);
+       flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
+       txq->axq_tx_inprogress = false;
+
+       txq->axq_depth--;
+       if (bf_is_ampdu_not_probing(bf))
+               txq->axq_ampdu_depth--;
+
+       if (!bf_isampdu(bf)) {
+               if (!flush)
+                       ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+               ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
+       } else
+               ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
+
+       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush)
+               ath_txq_schedule(sc, txq);
+}
+
 static bool ath_lookup_legacy(struct ath_buf *bf)
 {
        struct sk_buff *skb;
@@ -1331,23 +1362,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
 /* Queue Management */
 /********************/
 
-static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
-                                         struct ath_txq *txq)
-{
-       struct ath_atx_ac *ac, *ac_tmp;
-       struct ath_atx_tid *tid, *tid_tmp;
-
-       list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
-               list_del(&ac->list);
-               ac->sched = false;
-               list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
-                       list_del(&tid->list);
-                       tid->sched = false;
-                       ath_tid_drain(sc, txq, tid);
-               }
-       }
-}
-
 struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -1470,14 +1484,8 @@ int ath_cabq_update(struct ath_softc *sc)
        return 0;
 }
 
-static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
-{
-    struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
-    return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
-}
-
 static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
-                              struct list_head *list, bool retry_tx)
+                              struct list_head *list)
 {
        struct ath_buf *bf, *lastbf;
        struct list_head bf_head;
@@ -1499,16 +1507,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
 
                lastbf = bf->bf_lastbf;
                list_cut_position(&bf_head, list, &lastbf->list);
-
-               txq->axq_depth--;
-               if (bf_is_ampdu_not_probing(bf))
-                       txq->axq_ampdu_depth--;
-
-               if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
-                                            retry_tx);
-               else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
+               ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
        }
 }
 
@@ -1518,7 +1517,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
  * This assumes output has been stopped and
  * we do not need to block ath_tx_tasklet.
  */
-void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq)
 {
        ath_txq_lock(sc, txq);
 
@@ -1526,8 +1525,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
                int idx = txq->txq_tailidx;
 
                while (!list_empty(&txq->txq_fifo[idx])) {
-                       ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
-                                          retry_tx);
+                       ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]);
 
                        INCR(idx, ATH_TXFIFO_DEPTH);
                }
@@ -1536,16 +1534,12 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 
        txq->axq_link = NULL;
        txq->axq_tx_inprogress = false;
-       ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
-
-       /* flush any pending frames if aggregation is enabled */
-       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx)
-               ath_txq_drain_pending_buffers(sc, txq);
+       ath_drain_txq_list(sc, txq, &txq->axq_q);
 
        ath_txq_unlock_complete(sc, txq);
 }
 
-bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
+bool ath_drain_all_txq(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1581,7 +1575,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
                 */
                txq = &sc->tx.txq[i];
                txq->stopped = false;
-               ath_draintxq(sc, txq, retry_tx);
+               ath_draintxq(sc, txq);
        }
 
        return !npend;
@@ -2175,28 +2169,6 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
        tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
 }
 
-static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
-                                 struct ath_tx_status *ts, struct ath_buf *bf,
-                                 struct list_head *bf_head)
-{
-       int txok;
-
-       txq->axq_depth--;
-       txok = !(ts->ts_status & ATH9K_TXERR_MASK);
-       txq->axq_tx_inprogress = false;
-       if (bf_is_ampdu_not_probing(bf))
-               txq->axq_ampdu_depth--;
-
-       if (!bf_isampdu(bf)) {
-               ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
-               ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
-       } else
-               ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
-
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
-               ath_txq_schedule(sc, txq);
-}
-
 static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -2361,8 +2333,8 @@ static int ath_txstatus_setup(struct ath_softc *sc, int size)
        u8 txs_len = sc->sc_ah->caps.txs_len;
 
        dd->dd_desc_len = size * txs_len;
-       dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
-                                        &dd->dd_desc_paddr, GFP_KERNEL);
+       dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
+                                         &dd->dd_desc_paddr, GFP_KERNEL);
        if (!dd->dd_desc)
                return -ENOMEM;
 
@@ -2382,14 +2354,6 @@ static int ath_tx_edma_init(struct ath_softc *sc)
        return err;
 }
 
-static void ath_tx_edma_cleanup(struct ath_softc *sc)
-{
-       struct ath_descdma *dd = &sc->txsdma;
-
-       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-                         dd->dd_desc_paddr);
-}
-
 int ath_tx_init(struct ath_softc *sc, int nbufs)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -2402,7 +2366,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
        if (error != 0) {
                ath_err(common,
                        "Failed to allocate tx descriptors: %d\n", error);
-               goto err;
+               return error;
        }
 
        error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
@@ -2410,36 +2374,17 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
        if (error != 0) {
                ath_err(common,
                        "Failed to allocate beacon descriptors: %d\n", error);
-               goto err;
+               return error;
        }
 
        INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
 
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                error = ath_tx_edma_init(sc);
-               if (error)
-                       goto err;
-       }
-
-err:
-       if (error != 0)
-               ath_tx_cleanup(sc);
 
        return error;
 }
 
-void ath_tx_cleanup(struct ath_softc *sc)
-{
-       if (sc->beacon.bdma.dd_desc_len != 0)
-               ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
-
-       if (sc->tx.txdma.dd_desc_len != 0)
-               ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
-
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-               ath_tx_edma_cleanup(sc);
-}
-
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 {
        struct ath_atx_tid *tid;
index 2df17f1e49efca2ddb24f38a0145c4ce73225111..25599741cd8a5863fe3879afa288f07b05ead23a 100644 (file)
@@ -85,20 +85,14 @@ enum carl9170_device_state {
        CARL9170_STARTED,
 };
 
-#define CARL9170_NUM_TID               16
 #define WME_BA_BMP_SIZE                        64
 #define CARL9170_TX_USER_RATE_TRIES    3
 
-#define WME_AC_BE   2
-#define WME_AC_BK   3
-#define WME_AC_VI   1
-#define WME_AC_VO   0
-
 #define TID_TO_WME_AC(_tid)                            \
-       ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
-        (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
-        (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
-        WME_AC_VO)
+       ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE :   \
+        (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK :   \
+        (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI :   \
+        IEEE80211_AC_VO)
 
 #define SEQ_DIFF(_start, _seq) \
        (((_start) - (_seq)) & 0x0fff)
@@ -290,6 +284,7 @@ struct ar9170 {
                unsigned int rx_size;
                unsigned int tx_seq_table;
                bool ba_filter;
+               bool disable_offload_fw;
        } fw;
 
        /* interface configuration combinations */
@@ -493,8 +488,8 @@ struct carl9170_sta_info {
        bool sleeping;
        atomic_t pending_frames;
        unsigned int ampdu_max_len;
-       struct carl9170_sta_tid __rcu *agg[CARL9170_NUM_TID];
-       struct carl9170_ba_stats stats[CARL9170_NUM_TID];
+       struct carl9170_sta_tid __rcu *agg[IEEE80211_NUM_TIDS];
+       struct carl9170_ba_stats stats[IEEE80211_NUM_TIDS];
 };
 
 struct carl9170_tx_info {
index 63fd9af3fd39dd2c1d7ddb183902ae5e587b1ada..47d5c2e910ad834d81c8c22fe368e191be3d6e32 100644 (file)
@@ -215,6 +215,24 @@ static int carl9170_fw_tx_sequence(struct ar9170 *ar)
        return 0;
 }
 
+static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
+                                           u16 if_comb_types)
+{
+       if (ar->fw.vif_num < 2)
+               return;
+
+       ar->if_comb_limits[0].max = ar->fw.vif_num;
+       ar->if_comb_limits[0].types = if_comb_types;
+
+       ar->if_combs[0].num_different_channels = 1;
+       ar->if_combs[0].max_interfaces = ar->fw.vif_num;
+       ar->if_combs[0].limits = ar->if_comb_limits;
+       ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
+
+       ar->hw->wiphy->iface_combinations = ar->if_combs;
+       ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
+}
+
 static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
 {
        const struct carl9170fw_otus_desc *otus_desc;
@@ -264,7 +282,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
        if (!SUPP(CARL9170FW_COMMAND_CAM)) {
                dev_info(&ar->udev->dev, "crypto offloading is disabled "
                         "by firmware.\n");
-               ar->disable_offload = true;
+               ar->fw.disable_offload_fw = true;
        }
 
        if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
@@ -345,20 +363,15 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
                }
        }
 
-       ar->if_comb_limits[0].max = ar->fw.vif_num;
-       ar->if_comb_limits[0].types = if_comb_types;
-
-       ar->if_combs[0].num_different_channels = 1;
-       ar->if_combs[0].max_interfaces = ar->fw.vif_num;
-       ar->if_combs[0].limits = ar->if_comb_limits;
-       ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
-
-       ar->hw->wiphy->iface_combinations = ar->if_combs;
-       ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
+       carl9170_fw_set_if_combinations(ar, if_comb_types);
 
        ar->hw->wiphy->interface_modes |= if_comb_types;
 
-       ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+       ar->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       /* As IBSS Encryption is software-based, IBSS RSN is supported. */
+       ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_SUPPORTS_TDLS;
 
 #undef SUPPORTED
        return carl9170_fw_tx_sequence(ar);
index 9443c802b25b8578f6afd2b2cb66243ab47f34f1..9111d4ffc1b3851309af860a7b2e3e8175a2fb3e 100644 (file)
@@ -156,6 +156,14 @@ struct carl9170_psm {
 } __packed;
 #define CARL9170_PSM_SIZE              4
 
+/*
+ * Note: If a bit in rx_filter is set, then it
+ * means that the particular frames which matches
+ * the condition are FILTERED/REMOVED/DISCARDED!
+ * (This is can be a bit confusing, especially
+ * because someone people think it's the exact
+ * opposite way, so watch out!)
+ */
 struct carl9170_rx_filter_cmd {
        __le32          rx_filter;
 } __packed;
index fa834c1460f0033b4b6e1273952129d12750898a..0db874abde500750f7365ed6a9c254b297d03025 100644 (file)
 
 #define        AR9170_MAC_REG_BCN_ADDR                 (AR9170_MAC_REG_BASE + 0xd84)
 #define        AR9170_MAC_REG_BCN_LENGTH               (AR9170_MAC_REG_BASE + 0xd88)
-#define                AR9170_MAC_BCN_LENGTH_MAX               256
+#define                AR9170_MAC_BCN_LENGTH_MAX               (512 - 32)
 
 #define AR9170_MAC_REG_BCN_STATUS              (AR9170_MAC_REG_BASE + 0xd8c)
 
index 25a1e2f4f73862fb9bc26f6310d87bb3d51b6cf5..ef82751722e0bd4ae45c50ad18e705cee755222d 100644 (file)
@@ -358,8 +358,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
        ar->ps.last_action = jiffies;
        ar->ps.last_slept = jiffies;
        ar->erp_mode = CARL9170_ERP_AUTO;
-       ar->rx_software_decryption = false;
-       ar->disable_offload = false;
+
+       /* Set "disable hw crypto offload" whenever the module parameter
+        * nohwcrypt is true or if the firmware does not support it.
+        */
+       ar->disable_offload = modparam_nohwcrypt |
+               ar->fw.disable_offload_fw;
+       ar->rx_software_decryption = ar->disable_offload;
 
        for (i = 0; i < ar->hw->queues; i++) {
                ar->queue_stop_timeout[i] = jiffies;
@@ -565,12 +570,28 @@ static int carl9170_init_interface(struct ar9170 *ar,
 
        memcpy(common->macaddr, vif->addr, ETH_ALEN);
 
-       if (modparam_nohwcrypt ||
-           ((vif->type != NL80211_IFTYPE_STATION) &&
-            (vif->type != NL80211_IFTYPE_AP))) {
-               ar->rx_software_decryption = true;
-               ar->disable_offload = true;
-       }
+       /* We have to fall back to software crypto, whenever
+        * the user choose to participates in an IBSS. HW
+        * offload for IBSS RSN is not supported by this driver.
+        *
+        * NOTE: If the previous main interface has already
+        * disabled hw crypto offload, we have to keep this
+        * previous disable_offload setting as it was.
+        * Altough ideally, we should notify mac80211 and tell
+        * it to forget about any HW crypto offload for now.
+        */
+       ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) &&
+           (vif->type != NL80211_IFTYPE_AP));
+
+       /* While the driver supports HW offload in a single
+        * P2P client configuration, it doesn't support HW
+        * offload in the favourit, concurrent P2P GO+CLIENT
+        * configuration. Hence, HW offload will always be
+        * disabled for P2P.
+        */
+       ar->disable_offload |= vif->p2p;
+
+       ar->rx_software_decryption = ar->disable_offload;
 
        err = carl9170_set_operating_mode(ar);
        return err;
@@ -580,7 +601,7 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
        struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
-       struct ieee80211_vif *main_vif;
+       struct ieee80211_vif *main_vif, *old_main = NULL;
        struct ar9170 *ar = hw->priv;
        int vif_id = -1, err = 0;
 
@@ -602,6 +623,15 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
                goto init;
        }
 
+       /* Because the AR9170 HW's MAC doesn't provide full support for
+        * multiple, independent interfaces [of different operation modes].
+        * We have to select ONE main interface [main mode of HW], but we
+        * can have multiple slaves [AKA: entry in the ACK-table].
+        *
+        * The first (from HEAD/TOP) interface in the ar->vif_list is
+        * always the main intf. All following intfs in this list
+        * are considered to be slave intfs.
+        */
        main_vif = carl9170_get_main_vif(ar);
 
        if (main_vif) {
@@ -610,6 +640,18 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
                        if (vif->type == NL80211_IFTYPE_STATION)
                                break;
 
+                       /* P2P GO [master] use-case
+                        * Because the P2P GO station is selected dynamically
+                        * by all participating peers of a WIFI Direct network,
+                        * the driver has be able to change the main interface
+                        * operating mode on the fly.
+                        */
+                       if (main_vif->p2p && vif->p2p &&
+                           vif->type == NL80211_IFTYPE_AP) {
+                               old_main = main_vif;
+                               break;
+                       }
+
                        err = -EBUSY;
                        rcu_read_unlock();
 
@@ -648,14 +690,41 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
        vif_priv->id = vif_id;
        vif_priv->enable_beacon = false;
        ar->vifs++;
-       list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
+       if (old_main) {
+               /* We end up in here, if the main interface is being replaced.
+                * Put the new main interface at the HEAD of the list and the
+                * previous inteface will automatically become second in line.
+                */
+               list_add_rcu(&vif_priv->list, &ar->vif_list);
+       } else {
+               /* Add new inteface. If the list is empty, it will become the
+                * main inteface, otherwise it will be slave.
+                */
+               list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
+       }
        rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif);
 
 init:
-       if (carl9170_get_main_vif(ar) == vif) {
+       main_vif = carl9170_get_main_vif(ar);
+
+       if (main_vif == vif) {
                rcu_assign_pointer(ar->beacon_iter, vif_priv);
                rcu_read_unlock();
 
+               if (old_main) {
+                       struct carl9170_vif_info *old_main_priv =
+                               (void *) old_main->drv_priv;
+                       /* downgrade old main intf to slave intf.
+                        * NOTE: We are no longer under rcu_read_lock.
+                        * But we are still holding ar->mutex, so the
+                        * vif data [id, addr] is safe.
+                        */
+                       err = carl9170_mod_virtual_mac(ar, old_main_priv->id,
+                                                      old_main->addr);
+                       if (err)
+                               goto unlock;
+               }
+
                err = carl9170_init_interface(ar, vif);
                if (err)
                        goto unlock;
@@ -1112,9 +1181,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (ar->disable_offload || !vif)
                return -EOPNOTSUPP;
 
-       /*
-        * We have to fall back to software encryption, whenever
-        * the user choose to participates in an IBSS or is connected
+       /* Fall back to software encryption whenever the driver is connected
         * to more than one network.
         *
         * This is very unfortunate, because some machines cannot handle
@@ -1263,7 +1330,7 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw,
                        return 0;
                }
 
-               for (i = 0; i < CARL9170_NUM_TID; i++)
+               for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++)
                        RCU_INIT_POINTER(sta_info->agg[i], NULL);
 
                sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
@@ -1287,7 +1354,7 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
                sta_info->ht_sta = false;
 
                rcu_read_lock();
-               for (i = 0; i < CARL9170_NUM_TID; i++) {
+               for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) {
                        struct carl9170_sta_tid *tid_info;
 
                        tid_info = rcu_dereference(sta_info->agg[i]);
@@ -1394,7 +1461,9 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
 
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                rcu_read_lock();
                tid_info = rcu_dereference(sta_info->agg[tid]);
                if (tid_info) {
@@ -1805,10 +1874,6 @@ void *carl9170_alloc(size_t priv_size)
        for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
                ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
 
-       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
-       /* As IBSS Encryption is software-based, IBSS RSN is supported. */
-       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
        return ar;
 
 err_nomem:
@@ -1916,13 +1981,13 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
        return 0;
 }
 
-static int carl9170_reg_notifier(struct wiphy *wiphy,
-                                struct regulatory_request *request)
+static void carl9170_reg_notifier(struct wiphy *wiphy,
+                                 struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct ar9170 *ar = hw->priv;
 
-       return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
+       ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
 }
 
 int carl9170_register(struct ar9170 *ar)
index ef4ec0da6e498288cafe11ff6770b6eaf96d13e8..9c0b150d5b8e2a20b3373d91b733362f083df63a 100644 (file)
@@ -1520,35 +1520,92 @@ void carl9170_tx_scheduler(struct ar9170 *ar)
                carl9170_tx(ar);
 }
 
-int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
+/* caller has to take rcu_read_lock */
+static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
 {
-       struct sk_buff *skb = NULL;
        struct carl9170_vif_info *cvif;
+       int i = 1;
+
+       /* The AR9170 hardware has no fancy beacon queue or some
+        * other scheduling mechanism. So, the driver has to make
+        * due by setting the two beacon timers (pretbtt and tbtt)
+        * once and then swapping the beacon address in the HW's
+        * register file each time the pretbtt fires.
+        */
+
+       cvif = rcu_dereference(ar->beacon_iter);
+       if (ar->vifs > 0 && cvif) {
+               do {
+                       list_for_each_entry_continue_rcu(cvif, &ar->vif_list,
+                                                        list) {
+                               if (cvif->active && cvif->enable_beacon)
+                                       goto out;
+                       }
+               } while (ar->beacon_enabled && i--);
+       }
+
+out:
+       rcu_assign_pointer(ar->beacon_iter, cvif);
+       return cvif;
+}
+
+static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb,
+                                     u32 *ht1, u32 *plcp)
+{
        struct ieee80211_tx_info *txinfo;
        struct ieee80211_tx_rate *rate;
-       __le32 *data, *old = NULL;
-       unsigned int plcp, power, chains;
-       u32 word, ht1, off, addr, len;
-       int i = 0, err = 0;
+       unsigned int power, chains;
+       bool ht_rate;
 
-       rcu_read_lock();
-       cvif = rcu_dereference(ar->beacon_iter);
-retry:
-       if (ar->vifs == 0 || !cvif)
-               goto out_unlock;
+       txinfo = IEEE80211_SKB_CB(skb);
+       rate = &txinfo->control.rates[0];
+       ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS);
+       carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains);
 
-       list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
-               if (cvif->active && cvif->enable_beacon)
-                       goto found;
+       *ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
+       if (chains == AR9170_TX_PHY_TXCHAIN_2)
+               *ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
+       SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7);
+       SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power);
+       SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains);
+
+       if (ht_rate) {
+               *ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
+               if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+                       *plcp |= AR9170_MAC_BCN_HT2_SGI;
+
+               if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
+                       *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
+                       *plcp |= AR9170_MAC_BCN_HT2_BW40;
+               } else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
+                       *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
+                       *plcp |= AR9170_MAC_BCN_HT2_BW40;
+               }
+
+               SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN);
+       } else {
+               if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M)
+                       *plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
+               else
+                       *plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
        }
 
-       if (!ar->beacon_enabled || i++)
-               goto out_unlock;
+       return ht_rate;
+}
 
-       goto retry;
+int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
+{
+       struct sk_buff *skb = NULL;
+       struct carl9170_vif_info *cvif;
+       __le32 *data, *old = NULL;
+       u32 word, ht1, plcp, off, addr, len;
+       int i = 0, err = 0;
+       bool ht_rate;
 
-found:
-       rcu_assign_pointer(ar->beacon_iter, cvif);
+       rcu_read_lock();
+       cvif = carl9170_pick_beaconing_vif(ar);
+       if (!cvif)
+               goto out_unlock;
 
        skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
                NULL, NULL);
@@ -1558,7 +1615,6 @@ found:
                goto err_free;
        }
 
-       txinfo = IEEE80211_SKB_CB(skb);
        spin_lock_bh(&ar->beacon_lock);
        data = (__le32 *)skb->data;
        if (cvif->beacon)
@@ -1588,43 +1644,14 @@ found:
                goto err_unlock;
        }
 
-       ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
-       rate = &txinfo->control.rates[0];
-       carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains);
-       if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
-               if (plcp <= AR9170_TX_PHY_RATE_CCK_11M)
-                       plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
-               else
-                       plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
-       } else {
-               ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
-               if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
-                       plcp |= AR9170_MAC_BCN_HT2_SGI;
-
-               if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
-                       ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
-                       plcp |= AR9170_MAC_BCN_HT2_BW40;
-               }
-               if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
-                       ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
-                       plcp |= AR9170_MAC_BCN_HT2_BW40;
-               }
-
-               SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN);
-       }
-
-       SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7);
-       SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power);
-       SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains);
-       if (chains == AR9170_TX_PHY_TXCHAIN_2)
-               ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
+       ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp);
 
        carl9170_async_regwrite_begin(ar);
        carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1);
-       if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS))
-               carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
-       else
+       if (ht_rate)
                carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp);
+       else
+               carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
 
        for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
                /*
index 2ec3e9191e4dcc150272fe116d1087bfc93ef6a9..2282847d4bb898fa2f09f858f9530b9ae6191300 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __CARL9170_SHARED_VERSION_H
 #define __CARL9170_SHARED_VERSION_H
 #define CARL9170FW_VERSION_YEAR 12
-#define CARL9170FW_VERSION_MONTH 7
-#define CARL9170FW_VERSION_DAY 7
-#define CARL9170FW_VERSION_GIT "1.9.6"
+#define CARL9170FW_VERSION_MONTH 12
+#define CARL9170FW_VERSION_DAY 15
+#define CARL9170FW_VERSION_GIT "1.9.7"
 #endif /* __CARL9170_SHARED_VERSION_H */
index d81698015bf75897ae9d58fcf80e4ef6359e4be9..ccc4c718f124c2a500410cc9ed16f48841e8ec29 100644 (file)
@@ -195,8 +195,6 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
        const struct ieee80211_reg_rule *reg_rule;
        struct ieee80211_channel *ch;
        unsigned int i;
-       u32 bandwidth = 0;
-       int r;
 
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 
@@ -214,11 +212,8 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
                                continue;
 
                        if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                               r = freq_reg_info(wiphy,
-                                                 ch->center_freq,
-                                                 bandwidth,
-                                                 &reg_rule);
-                               if (r)
+                               reg_rule = freq_reg_info(wiphy, ch->center_freq);
+                               if (IS_ERR(reg_rule))
                                        continue;
                                /*
                                 * If 11d had a rule for this channel ensure
@@ -254,8 +249,6 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *ch;
        const struct ieee80211_reg_rule *reg_rule;
-       u32 bandwidth = 0;
-       int r;
 
        sband = wiphy->bands[IEEE80211_BAND_2GHZ];
        if (!sband)
@@ -283,16 +276,16 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
         */
 
        ch = &sband->channels[11]; /* CH 12 */
-       r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-       if (!r) {
+       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       if (!IS_ERR(reg_rule)) {
                if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
                        if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
                                ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
        }
 
        ch = &sband->channels[12]; /* CH 13 */
-       r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-       if (!r) {
+       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       if (!IS_ERR(reg_rule)) {
                if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
                        if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
                                ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -363,9 +356,9 @@ static u16 ath_regd_find_country_by_name(char *alpha2)
        return -1;
 }
 
-int ath_reg_notifier_apply(struct wiphy *wiphy,
-                          struct regulatory_request *request,
-                          struct ath_regulatory *reg)
+void ath_reg_notifier_apply(struct wiphy *wiphy,
+                           struct regulatory_request *request,
+                           struct ath_regulatory *reg)
 {
        struct ath_common *common = container_of(reg, struct ath_common,
                                                 regulatory);
@@ -380,7 +373,7 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
         * any pending requests in the queue.
         */
        if (!request)
-               return 0;
+               return;
 
        switch (request->initiator) {
        case NL80211_REGDOM_SET_BY_CORE:
@@ -416,8 +409,6 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
 
                break;
        }
-
-       return 0;
 }
 EXPORT_SYMBOL(ath_reg_notifier_apply);
 
@@ -507,8 +498,8 @@ ath_get_regpair(int regdmn)
 static int
 ath_regd_init_wiphy(struct ath_regulatory *reg,
                    struct wiphy *wiphy,
-                   int (*reg_notifier)(struct wiphy *wiphy,
-                                       struct regulatory_request *request))
+                   void (*reg_notifier)(struct wiphy *wiphy,
+                                        struct regulatory_request *request))
 {
        const struct ieee80211_regdomain *regd;
 
@@ -628,8 +619,8 @@ static int __ath_regd_init(struct ath_regulatory *reg)
 int
 ath_regd_init(struct ath_regulatory *reg,
              struct wiphy *wiphy,
-             int (*reg_notifier)(struct wiphy *wiphy,
-                                 struct regulatory_request *request))
+             void (*reg_notifier)(struct wiphy *wiphy,
+                                  struct regulatory_request *request))
 {
        struct ath_common *common = container_of(reg, struct ath_common,
                                                 regulatory);
index 03a8268ccf21a7ca9d9c8ccf9a836c7b0d402d57..37f53bd8fcb13ad1b7f850924383a4e9a297f7af 100644 (file)
@@ -252,12 +252,12 @@ enum CountryCode {
 bool ath_is_world_regd(struct ath_regulatory *reg);
 bool ath_is_49ghz_allowed(u16 redomain);
 int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
-                 int (*reg_notifier)(struct wiphy *wiphy,
-                 struct regulatory_request *request));
+                 void (*reg_notifier)(struct wiphy *wiphy,
+                                      struct regulatory_request *request));
 u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
                          enum ieee80211_band band);
-int ath_reg_notifier_apply(struct wiphy *wiphy,
-                          struct regulatory_request *request,
-                          struct ath_regulatory *reg);
+void ath_reg_notifier_apply(struct wiphy *wiphy,
+                           struct regulatory_request *request,
+                           struct ath_regulatory *reg);
 
 #endif
index 97d4e27bf36f3c3f14b336086efe770dbf671f77..aaca60c6f57518a0adfc60b9f61ecbc6d074440a 100644 (file)
@@ -3226,8 +3226,6 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
 {
        struct nphy_gain_ctl_workaround_entry *e;
        u8 phy_idx;
-       u8 tr_iso = ghz5 ? dev->dev->bus_sprom->fem.ghz5.tr_iso :
-                          dev->dev->bus_sprom->fem.ghz2.tr_iso;
 
        if (!ghz5 && dev->phy.rev >= 6 && dev->phy.radio_rev == 11)
                return &nphy_gain_ctl_wa_phy6_radio11_ghz2;
@@ -3249,6 +3247,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
                    !b43_channel_type_is_40mhz(dev->phy.channel_type))
                        e->cliplo_gain = 0x2d;
        } else if (!ghz5 && dev->phy.rev >= 5) {
+               static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
+                                               0x106c, 0x1074, 0x107c, 0x207c};
+               u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
+
                if (ext_lna) {
                        e->rfseq_init[0] &= ~0x4000;
                        e->rfseq_init[1] &= ~0x4000;
@@ -3256,26 +3258,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
                        e->rfseq_init[3] &= ~0x4000;
                        e->init_gain &= ~0x4000;
                }
-               switch (tr_iso) {
-               case 0:
-                       e->cliplo_gain = 0x0062;
-               case 1:
-                       e->cliplo_gain = 0x0064;
-               case 2:
-                       e->cliplo_gain = 0x006a;
-               case 3:
-                       e->cliplo_gain = 0x106a;
-               case 4:
-                       e->cliplo_gain = 0x106c;
-               case 5:
-                       e->cliplo_gain = 0x1074;
-               case 6:
-                       e->cliplo_gain = 0x107c;
-               case 7:
-                       e->cliplo_gain = 0x207c;
-               default:
-                       e->cliplo_gain = 0x106a;
-               }
+               if (tr_iso > 7)
+                       tr_iso = 3;
+               e->cliplo_gain = gain_data[tr_iso];
+
        } else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
                e->rfseq_init[0] &= ~0x4000;
                e->rfseq_init[1] &= ~0x4000;
index be35a2f99b1cf3fce453e89bdacddacc84806ed1..11fd1c735589f31ab12789ec1067ad143c9a75ce 100644 (file)
@@ -15,8 +15,6 @@
  */
 /* ****************** SDIO CARD Interface Functions **************************/
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/export.h>
index d33e5598611bbad54808a69aa85b492137ce9df9..d92d373733d74a93b8d9fe6440792ebda5496d7d 100644 (file)
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/mmc/sdio.h>
index fd672bf53867f6b7aac803fae15686d0d750ccee..a2f32fb990fa9baa6d2d8b3803f6139bdb32996d 100644 (file)
@@ -39,6 +39,7 @@
 #define BRCMF_C_GET_BSSID                      23
 #define BRCMF_C_GET_SSID                       25
 #define BRCMF_C_SET_SSID                       26
+#define BRCMF_C_TERMINATED                     28
 #define BRCMF_C_GET_CHANNEL                    29
 #define BRCMF_C_SET_CHANNEL                    30
 #define BRCMF_C_GET_SRL                                31
@@ -480,36 +481,14 @@ struct brcmf_pub {
        unsigned long drv_version;      /* Version of dongle-resident driver */
        u8 mac[ETH_ALEN];               /* MAC address obtained from dongle */
 
-       /* Additional stats for the bus level */
-
        /* Multicast data packets sent to dongle */
        unsigned long tx_multicast;
-       /* Packets flushed due to unscheduled sendup thread */
-       unsigned long rx_flushed;
-       /* Number of times dpc scheduled by watchdog timer */
-       unsigned long wd_dpc_sched;
-
-       /* Number of flow control pkts recvd */
-       unsigned long fc_packets;
-
-       /* Last error return */
-       int bcmerror;
-
-       /* Last error from dongle */
-       int dongle_error;
-
-       /* Suspend disable flag  flag */
-       int suspend_disable_flag;       /* "1" to disable all extra powersaving
-                                        during suspend */
-       int in_suspend;         /* flag set to 1 when early suspend called */
-       int dtim_skip;          /* dtim skip , default 0 means wake each dtim */
 
        struct brcmf_if *iflist[BRCMF_MAX_IFS];
 
        struct mutex proto_block;
        unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 
-       u8 macvalue[ETH_ALEN];
        atomic_t pend_8021x_cnt;
        wait_queue_head_t pend_8021x_wait;
 
@@ -519,11 +498,6 @@ struct brcmf_pub {
 #endif
 };
 
-struct bcmevent_name {
-       uint event;
-       const char *name;
-};
-
 struct brcmf_if_event {
        u8 ifidx;
        u8 action;
@@ -557,13 +531,6 @@ struct brcmf_if {
        u8 mac_addr[ETH_ALEN];
 };
 
-static inline s32 brcmf_ndev_bssidx(struct net_device *ndev)
-{
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       return ifp->bssidx;
-}
-
-extern const struct bcmevent_name bcmevent_names[];
 
 extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
 
@@ -576,6 +543,10 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
 extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
                                    void *buf, uint len);
 
+/* Remove any protocol-specific data header. */
+extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
+                              struct sk_buff *rxp);
+
 extern int brcmf_net_attach(struct brcmf_if *ifp);
 extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx,
                                     s32 bssidx, char *name, u8 *mac_addr);
index dd38b78a9726f75861bcb1f92ef3d511a81b92db..64c38f4226a3f145b57973a9369bd0f03f9040a4 100644 (file)
@@ -130,31 +130,18 @@ int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
  * interface functions from common layer
  */
 
-/* Remove any protocol-specific data header. */
-extern int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
-                              struct sk_buff *rxp);
-
 extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
                         struct sk_buff *pkt, int prec);
 
 /* Receive frame for delivery to OS.  Callee disposes of rxp. */
-extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
-                          struct sk_buff_head *rxlist);
-static inline void brcmf_rx_packet(struct device *dev, int ifidx,
-                                  struct sk_buff *pkt)
-{
-       struct sk_buff_head q;
-
-       skb_queue_head_init(&q);
-       skb_queue_tail(&q, pkt);
-       brcmf_rx_frame(dev, ifidx, &q);
-}
+extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist);
 
 /* Indication from bus module regarding presence/insertion of dongle. */
 extern int brcmf_attach(uint bus_hdrlen, struct device *dev);
 /* Indication from bus module regarding removal/absence of dongle */
 extern void brcmf_detach(struct device *dev);
-
+/* Indication from bus module that dongle should be reset */
+extern void brcmf_dev_reset(struct device *dev);
 /* Indication from bus module to change flow-control state */
 extern void brcmf_txflowblock(struct device *dev, bool state);
 
index 83923553f1ac2cff41acda4677a5fd7cb54d7efd..bb454cdab29dece758af990c35a20c2484cd78a7 100644 (file)
@@ -19,8 +19,6 @@
  * For certain dcmd codes, the dongle interprets string data from the host.
  ******************************************************************************/
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 
@@ -94,8 +92,6 @@ struct brcmf_proto_bdc_header {
 
 struct brcmf_proto {
        u16 reqid;
-       u8 pending;
-       u32 lastcmd;
        u8 bus_header[BUS_HEADER_LEN];
        struct brcmf_proto_cdc_dcmd msg;
        unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
@@ -107,7 +103,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
        int len = le32_to_cpu(prot->msg.len) +
                        sizeof(struct brcmf_proto_cdc_dcmd);
 
-       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(CDC, "Enter\n");
 
        /* NOTE : cdc->msg.len holds the desired length of the buffer to be
         *        returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
@@ -125,7 +121,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
        int ret;
        struct brcmf_proto *prot = drvr->prot;
 
-       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(CDC, "Enter\n");
        len += sizeof(struct brcmf_proto_cdc_dcmd);
        do {
                ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg,
@@ -147,20 +143,7 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
        int ret = 0, retries = 0;
        u32 id, flags;
 
-       brcmf_dbg(TRACE, "Enter\n");
-       brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
-
-       /* Respond "bcmerror" and "bcmerrorstr" with local cache */
-       if (cmd == BRCMF_C_GET_VAR && buf) {
-               if (!strcmp((char *)buf, "bcmerrorstr")) {
-                       strncpy((char *)buf, "bcm_error",
-                               BCME_STRLEN);
-                       goto done;
-               } else if (!strcmp((char *)buf, "bcmerror")) {
-                       *(int *)buf = drvr->dongle_error;
-                       goto done;
-               }
-       }
+       brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
 
        memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
 
@@ -210,11 +193,8 @@ retry:
        }
 
        /* Check the ERROR flag */
-       if (flags & CDC_DCMD_ERROR) {
+       if (flags & CDC_DCMD_ERROR)
                ret = le32_to_cpu(msg->status);
-               /* Cache error from dongle */
-               drvr->dongle_error = ret;
-       }
 
 done:
        return ret;
@@ -228,8 +208,7 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
        int ret = 0;
        u32 flags, id;
 
-       brcmf_dbg(TRACE, "Enter\n");
-       brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
+       brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
 
        memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
 
@@ -262,11 +241,8 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
        }
 
        /* Check the ERROR flag */
-       if (flags & CDC_DCMD_ERROR) {
+       if (flags & CDC_DCMD_ERROR)
                ret = le32_to_cpu(msg->status);
-               /* Cache error from dongle */
-               drvr->dongle_error = ret;
-       }
 
 done:
        return ret;
@@ -287,7 +263,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
 {
        struct brcmf_proto_bdc_header *h;
 
-       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(CDC, "Enter\n");
 
        /* Push BDC header used to convey priority for buses that don't */
 
@@ -305,14 +281,12 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
        BDC_SET_IF_IDX(h, ifidx);
 }
 
-int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
+int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
                        struct sk_buff *pktbuf)
 {
        struct brcmf_proto_bdc_header *h;
-       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_pub *drvr = bus_if->drvr;
 
-       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(CDC, "Enter\n");
 
        /* Pop BDC header used to convey priority for buses that don't */
 
@@ -338,7 +312,7 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
        }
 
        if (h->flags & BDC_FLAG_SUM_GOOD) {
-               brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n",
+               brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
                          brcmf_ifname(drvr, *ifidx), h->flags);
                pkt_set_sum_good(pktbuf, true);
        }
@@ -348,6 +322,8 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
        skb_pull(pktbuf, BDC_HEADER_LEN);
        skb_pull(pktbuf, h->data_offset << 2);
 
+       if (pktbuf->len == 0)
+               return -ENODATA;
        return 0;
 }
 
index f8b52e5b941a7b3c738701a067a92eae2b84c7e9..4544342a04281d84e67fd93222a50ce3ac2fdc7c 100644 (file)
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/netdevice.h>
index f2ab01cd796600643c94f6e98da09429d2cbedaf..bc013cbe06f611647829694b97277423e43a7d5e 100644 (file)
 #define _BRCMF_DBG_H_
 
 /* message levels */
-#define BRCMF_TRACE_VAL        0x0002
-#define BRCMF_INFO_VAL 0x0004
-#define BRCMF_DATA_VAL 0x0008
-#define BRCMF_CTL_VAL  0x0010
-#define BRCMF_TIMER_VAL        0x0020
-#define BRCMF_HDRS_VAL 0x0040
-#define BRCMF_BYTES_VAL        0x0080
-#define BRCMF_INTR_VAL 0x0100
-#define BRCMF_GLOM_VAL 0x0200
-#define BRCMF_EVENT_VAL        0x0400
-#define BRCMF_BTA_VAL  0x0800
-#define BRCMF_FIL_VAL  0x1000
-#define BRCMF_USB_VAL  0x2000
-#define BRCMF_SCAN_VAL 0x4000
-#define BRCMF_CONN_VAL 0x8000
+#define BRCMF_TRACE_VAL        0x00000002
+#define BRCMF_INFO_VAL 0x00000004
+#define BRCMF_DATA_VAL 0x00000008
+#define BRCMF_CTL_VAL  0x00000010
+#define BRCMF_TIMER_VAL        0x00000020
+#define BRCMF_HDRS_VAL 0x00000040
+#define BRCMF_BYTES_VAL        0x00000080
+#define BRCMF_INTR_VAL 0x00000100
+#define BRCMF_GLOM_VAL 0x00000200
+#define BRCMF_EVENT_VAL        0x00000400
+#define BRCMF_BTA_VAL  0x00000800
+#define BRCMF_FIL_VAL  0x00001000
+#define BRCMF_USB_VAL  0x00002000
+#define BRCMF_SCAN_VAL 0x00004000
+#define BRCMF_CONN_VAL 0x00008000
+#define BRCMF_CDC_VAL  0x00010000
+
+/* set default print format */
+#undef pr_fmt
+#define pr_fmt(fmt)            KBUILD_MODNAME ": " fmt
 
 /* Macro for error messages. net_ratelimit() is used when driver
  * debugging is not selected. When debugging the driver error
index 74a616b4de8e027c5f877f2910a526fed9d29aa3..14b8fdde69542fe54f8fd33aef11022e4bdfd65f 100644 (file)
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
 #include <linux/module.h>
@@ -162,28 +160,31 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
        schedule_work(&ifp->multicast_work);
 }
 
-static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
+                                          struct net_device *ndev)
 {
        int ret;
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_pub *drvr = ifp->drvr;
+       struct ethhdr *eh;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /* Reject if down */
-       if (!drvr->bus_if->drvr_up ||
-           (drvr->bus_if->state != BRCMF_BUS_DATA)) {
-               brcmf_err("xmit rejected drvup=%d state=%d\n",
-                         drvr->bus_if->drvr_up,
-                         drvr->bus_if->state);
+       /* Can the device send data? */
+       if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+               brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
                netif_stop_queue(ndev);
-               return -ENODEV;
+               dev_kfree_skb(skb);
+               ret = -ENODEV;
+               goto done;
        }
 
        if (!drvr->iflist[ifp->idx]) {
                brcmf_err("bad ifidx %d\n", ifp->idx);
                netif_stop_queue(ndev);
-               return -ENODEV;
+               dev_kfree_skb(skb);
+               ret = -ENODEV;
+               goto done;
        }
 
        /* Make sure there's enough room for any header */
@@ -204,17 +205,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                }
        }
 
-       /* Update multicast statistic */
-       if (skb->len >= ETH_ALEN) {
-               u8 *pktdata = (u8 *)(skb->data);
-               struct ethhdr *eh = (struct ethhdr *)pktdata;
-
-               if (is_multicast_ether_addr(eh->h_dest))
-                       drvr->tx_multicast++;
-               if (ntohs(eh->h_proto) == ETH_P_PAE)
-                       atomic_inc(&drvr->pend_8021x_cnt);
+       /* validate length for ether packet */
+       if (skb->len < sizeof(*eh)) {
+               ret = -EINVAL;
+               dev_kfree_skb(skb);
+               goto done;
        }
 
+       /* handle ethernet header */
+       eh = (struct ethhdr *)(skb->data);
+       if (is_multicast_ether_addr(eh->h_dest))
+               drvr->tx_multicast++;
+       if (ntohs(eh->h_proto) == ETH_P_PAE)
+               atomic_inc(&drvr->pend_8021x_cnt);
+
        /* If the protocol uses a data header, apply it */
        brcmf_proto_hdrpush(drvr, ifp->idx, skb);
 
@@ -228,7 +232,7 @@ done:
                drvr->bus_if->dstats.tx_packets++;
 
        /* Return ok: we always eat the packet */
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 void brcmf_txflowblock(struct device *dev, bool state)
@@ -250,8 +254,7 @@ void brcmf_txflowblock(struct device *dev, bool state)
                }
 }
 
-void brcmf_rx_frame(struct device *dev, u8 ifidx,
-                   struct sk_buff_head *skb_list)
+void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 {
        unsigned char *eth;
        uint len;
@@ -259,12 +262,24 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
        struct brcmf_if *ifp;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
+       u8 ifidx;
+       int ret;
 
        brcmf_dbg(TRACE, "Enter\n");
 
        skb_queue_walk_safe(skb_list, skb, pnext) {
                skb_unlink(skb, skb_list);
 
+               /* process and remove protocol-specific header
+                */
+               ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
+               if (ret < 0) {
+                       if (ret != -ENODATA)
+                               bus_if->dstats.rx_errors++;
+                       brcmu_pkt_buf_free_skb(skb);
+                       continue;
+               }
+
                /* Get the protocol, maintain skb around eth_type_trans()
                 * The main reason for this hack is for the limitation of
                 * Linux 2.4 where 'eth_type_trans' uses the
@@ -328,13 +343,13 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
 
 void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
 {
-       uint ifidx;
+       u8 ifidx;
        struct ethhdr *eh;
        u16 type;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
 
-       brcmf_proto_hdrpull(dev, &ifidx, txp);
+       brcmf_proto_hdrpull(drvr, &ifidx, txp);
 
        eh = (struct ethhdr *)(txp->data);
        type = ntohs(eh->h_proto);
@@ -395,9 +410,11 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_pub *drvr = ifp->drvr;
 
-       sprintf(info->driver, KBUILD_MODNAME);
-       sprintf(info->version, "%lu", drvr->drv_version);
-       sprintf(info->bus_info, "%s", dev_name(drvr->bus_if->dev));
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       snprintf(info->version, sizeof(info->version), "%lu",
+                drvr->drv_version);
+       strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
+               sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops brcmf_ethtool_ops = {
@@ -450,7 +467,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
                sprintf(info.version, "%lu", drvr->drv_version);
                if (copy_to_user(uaddr, &info, sizeof(info)))
                        return -EFAULT;
-               brcmf_dbg(CTL, "given %*s, returning %s\n",
+               brcmf_dbg(TRACE, "given %*s, returning %s\n",
                          (int)sizeof(drvname), drvname, info.driver);
                break;
 
@@ -570,14 +587,9 @@ static int brcmf_netdev_open(struct net_device *ndev)
        /* Get current TOE mode from dongle */
        if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
            && (toe_ol & TOE_TX_CSUM_OL) != 0)
-               drvr->iflist[ifp->idx]->ndev->features |=
-                       NETIF_F_IP_CSUM;
+               ndev->features |= NETIF_F_IP_CSUM;
        else
-               drvr->iflist[ifp->idx]->ndev->features &=
-                       ~NETIF_F_IP_CSUM;
-
-       /* make sure RF is ready for work */
-       brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
+               ndev->features &= ~NETIF_F_IP_CSUM;
 
        /* Allow transmit calls */
        netif_start_queue(ndev);
@@ -845,6 +857,17 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
        }
 }
 
+void brcmf_dev_reset(struct device *dev)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
+
+       if (drvr == NULL)
+               return;
+
+       brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
+}
+
 void brcmf_detach(struct device *dev)
 {
        int i;
@@ -866,9 +889,8 @@ void brcmf_detach(struct device *dev)
 
        brcmf_bus_detach(drvr);
 
-       if (drvr->prot) {
+       if (drvr->prot)
                brcmf_proto_detach(drvr);
-       }
 
        brcmf_debugfs_detach(drvr);
        bus_if->drvr = NULL;
index cf857f1edf8c3b84d2d92c5f2b41874fae88ea82..7fef9b5ba00364b2c65d88049e580a06288e0032 100644 (file)
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
@@ -1169,7 +1167,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
        int errcode;
        u8 doff, sfdoff;
 
-       int ifidx = 0;
        bool usechain = bus->use_rxchain;
 
        struct brcmf_sdio_read rd_new;
@@ -1388,13 +1385,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                skb_unlink(pfirst, &bus->glom);
                                brcmu_pkt_buf_free_skb(pfirst);
                                continue;
-                       } else if (brcmf_proto_hdrpull(bus->sdiodev->dev,
-                                                      &ifidx, pfirst) != 0) {
-                               brcmf_err("rx protocol error\n");
-                               bus->sdiodev->bus_if->dstats.rx_errors++;
-                               skb_unlink(pfirst, &bus->glom);
-                               brcmu_pkt_buf_free_skb(pfirst);
-                               continue;
                        }
 
                        brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
@@ -1407,7 +1397,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                }
                /* sent any remaining packets up */
                if (bus->glom.qlen)
-                       brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
+                       brcmf_rx_frames(bus->sdiodev->dev, &bus->glom);
 
                bus->sdcnt.rxglomframes++;
                bus->sdcnt.rxglompkts += bus->glom.qlen;
@@ -1558,10 +1548,10 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
 static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 {
        struct sk_buff *pkt;            /* Packet for event or data frames */
+       struct sk_buff_head pktlist;    /* needed for bus interface */
        u16 pad;                /* Number of pad bytes to read */
        uint rxleft = 0;        /* Remaining number of frames allowed */
        int sdret;              /* Return code from calls */
-       int ifidx = 0;
        uint rxcount = 0;       /* Total frames read */
        struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
        u8 head_read = 0;
@@ -1760,15 +1750,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                if (pkt->len == 0) {
                        brcmu_pkt_buf_free_skb(pkt);
                        continue;
-               } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx,
-                          pkt) != 0) {
-                       brcmf_err("rx protocol error\n");
-                       brcmu_pkt_buf_free_skb(pkt);
-                       bus->sdiodev->bus_if->dstats.rx_errors++;
-                       continue;
                }
 
-               brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
+               skb_queue_head_init(&pktlist);
+               skb_queue_tail(&pktlist, pkt);
+               brcmf_rx_frames(bus->sdiodev->dev, &pktlist);
        }
 
        rxcount = maxframes - rxleft;
index b1bb46c49799f6391503fdca17ee81116eb32583..14be2d5530cebe3498a010cec9ba8bd09cabd0b6 100644 (file)
@@ -15,8 +15,6 @@
  */
 /* ***** SDIO interface chip backplane handle functions ***** */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/mmc/card.h>
index 914c56fe6c5f72ec260e27779ebac182b3d2dd0a..e15630cc3889fcb5f4644e9332ad60ecb68d679f 100644 (file)
@@ -443,14 +443,15 @@ static void brcmf_usb_rx_complete(struct urb *urb)
        struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;
        struct brcmf_usbdev_info *devinfo = req->devinfo;
        struct sk_buff *skb;
-       int ifidx = 0;
+       struct sk_buff_head skbq;
 
        brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
        brcmf_usb_del_fromq(devinfo, req);
        skb = req->skb;
        req->skb = NULL;
 
-       if (urb->status == 0) {
+       /* zero lenght packets indicate usb "failure". Do not refill */
+       if (urb->status == 0 && urb->actual_length) {
                devinfo->bus_pub.bus->dstats.rx_packets++;
        } else {
                devinfo->bus_pub.bus->dstats.rx_errors++;
@@ -460,13 +461,10 @@ static void brcmf_usb_rx_complete(struct urb *urb)
        }
 
        if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
+               skb_queue_head_init(&skbq);
+               skb_queue_tail(&skbq, skb);
                skb_put(skb, urb->actual_length);
-               if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
-                       brcmf_err("rx protocol error\n");
-                       brcmu_pkt_buf_free_skb(skb);
-                       devinfo->bus_pub.bus->dstats.rx_errors++;
-               } else
-                       brcmf_rx_packet(devinfo->dev, ifidx, skb);
+               brcmf_rx_frames(devinfo->dev, &skbq);
                brcmf_usb_rx_refill(devinfo, req);
        } else {
                brcmu_pkt_buf_free_skb(skb);
@@ -1520,10 +1518,23 @@ static void brcmf_release_fw(struct list_head *q)
        }
 }
 
+static int brcmf_usb_reset_device(struct device *dev, void *notused)
+{
+       /* device past is the usb interface so we
+        * need to use parent here.
+        */
+       brcmf_dev_reset(dev->parent);
+       return 0;
+}
 
 void brcmf_usb_exit(void)
 {
+       struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
+       int ret;
+
        brcmf_dbg(USB, "Enter\n");
+       ret = driver_for_each_device(drv, NULL, NULL,
+                                    brcmf_usb_reset_device);
        usb_deregister(&brcmf_usbdrvr);
        brcmf_release_fw(&fw_image_list);
 }
index 75464ad4fbd188ce1fb135302539dfa02caa3fbb..62a528e8b958bf03200fe1d87520db5bbb2b5cb9 100644 (file)
@@ -16,8 +16,6 @@
 
 /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
 #include <net/cfg80211.h>
@@ -2011,67 +2009,6 @@ done:
        return err;
 }
 
-static s32
-brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
-                            const u8 *addr,
-                            const struct cfg80211_bitrate_mask *mask)
-{
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcm_rateset_le rateset_le;
-       s32 rate;
-       s32 val;
-       s32 err_bg;
-       s32 err_a;
-       u32 legacy;
-       s32 err = 0;
-
-       brcmf_dbg(TRACE, "Enter\n");
-       if (!check_vif_up(ifp->vif))
-               return -EIO;
-
-       /* addr param is always NULL. ignore it */
-       /* Get current rateset */
-       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET,
-                                    &rateset_le, sizeof(rateset_le));
-       if (err) {
-               brcmf_err("could not get current rateset (%d)\n", err);
-               goto done;
-       }
-
-       legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
-       if (!legacy)
-               legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
-                            0xFFFF);
-
-       val = wl_g_rates[legacy - 1].bitrate * 100000;
-
-       if (val < le32_to_cpu(rateset_le.count))
-               /* Select rate by rateset index */
-               rate = rateset_le.rates[val] & 0x7f;
-       else
-               /* Specified rate in bps */
-               rate = val / 500000;
-
-       brcmf_dbg(CONN, "rate %d mbps\n", rate / 2);
-
-       /*
-        *
-        *      Set rate override,
-        *      Since the is a/b/g-blind, both a/bg_rate are enforced.
-        */
-       err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
-       err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
-       if (err_bg && err_a) {
-               brcmf_err("could not set fixed rate (%d) (%d)\n", err_bg,
-                         err_a);
-               err = err_bg | err_a;
-       }
-
-done:
-       brcmf_dbg(TRACE, "Exit\n");
-       return err;
-}
-
 static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
                                   struct brcmf_bss_info_le *bi)
 {
@@ -3704,7 +3641,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
        .set_default_key = brcmf_cfg80211_config_default_key,
        .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
        .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
-       .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
        .connect = brcmf_cfg80211_connect,
        .disconnect = brcmf_cfg80211_disconnect,
        .suspend = brcmf_cfg80211_suspend,
@@ -4330,9 +4266,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 }
 
 static s32
-brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
+brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
 {
-       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
        __le32 roamtrigger[2];
        __le32 roam_delta[2];
@@ -4383,10 +4318,9 @@ dongle_rom_out:
 }
 
 static s32
-brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
                      s32 scan_unassoc_time, s32 scan_passive_time)
 {
-       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
 
        err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
@@ -4456,6 +4390,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
 {
        struct net_device *ndev;
        struct wireless_dev *wdev;
+       struct brcmf_if *ifp;
        s32 power_mode;
        s32 err = 0;
 
@@ -4464,35 +4399,34 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
 
        ndev = cfg_to_ndev(cfg);
        wdev = ndev->ieee80211_ptr;
+       ifp = netdev_priv(ndev);
 
-       brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
-                       WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
+       /* make sure RF is ready for work */
+       brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
+
+       brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
+                             WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
 
        power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
-       err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
-                                   power_mode);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
        if (err)
                goto default_conf_out;
        brcmf_dbg(INFO, "power save set to %s\n",
                  (power_mode ? "enabled" : "disabled"));
 
-       err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
-                               WL_BEACON_TIMEOUT);
+       err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
        if (err)
                goto default_conf_out;
        err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
                                          NULL, NULL);
-       if (err && err != -EINPROGRESS)
+       if (err)
                goto default_conf_out;
        err = brcmf_dongle_probecap(cfg);
        if (err)
                goto default_conf_out;
 
-       /* -EINPROGRESS: Call commit handler */
-
-default_conf_out:
-
        cfg->dongle_up = true;
+default_conf_out:
 
        return err;
 
@@ -4501,8 +4435,6 @@ default_conf_out:
 static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
 {
        set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
-       if (ifp->idx)
-               return 0;
 
        return brcmf_config_dongle(ifp->drvr->config);
 }
index 1de94f30564fe8291c99657ced06d33ff6af2e5b..1585cc5bf866b847e86f6210074b4c89b6c0b26f 100644 (file)
@@ -961,7 +961,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                        /* if acked then clear bit and free packet */
                        if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
                            && isset(bitmap, bindex)) {
-                               ini->tx_in_transit--;
                                ini->txretry[index] = 0;
 
                                /*
@@ -990,7 +989,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                        if (retry && (ini->txretry[index] < (int)retry_limit)) {
                                int ret;
                                ini->txretry[index]++;
-                               ini->tx_in_transit--;
                                ret = brcms_c_txfifo(wlc, queue, p);
                                /*
                                 * We shouldn't be out of space in the DMA
@@ -1000,7 +998,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                                WARN_ONCE(ret, "queue %d out of txds\n", queue);
                        } else {
                                /* Retry timeout */
-                               ini->tx_in_transit--;
                                ieee80211_tx_info_clear_status(tx_info);
                                tx_info->status.ampdu_ack_len = 0;
                                tx_info->status.ampdu_len = 1;
@@ -1009,8 +1006,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                                skb_pull(p, D11_PHY_HDR_LEN);
                                skb_pull(p, D11_TXH_LEN);
                                brcms_dbg_ht(wlc->hw->d11core,
-                                            "BA Timeout, seq %d, in_transit %d\n",
-                                            seq, ini->tx_in_transit);
+                                            "BA Timeout, seq %d\n",
+                                            seq);
                                ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
                                                            p);
                        }
index a90b72202ec5a298b9cf6483cd5380ae5ef74ef0..cdb62b8ccc79c6c6ad6ea68269d3f03008d6e3e3 100644 (file)
@@ -670,7 +670,7 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *ch;
        const struct ieee80211_reg_rule *rule;
-       int band, i, ret;
+       int band, i;
 
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                sband = wiphy->bands[band];
@@ -685,9 +685,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
                                continue;
 
                        if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                               ret = freq_reg_info(wiphy, ch->center_freq,
-                                                   0, &rule);
-                               if (ret)
+                               rule = freq_reg_info(wiphy, ch->center_freq);
+                               if (IS_ERR(rule))
                                        continue;
 
                                if (!(rule->flags & NL80211_RRF_NO_IBSS))
@@ -703,8 +702,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
        }
 }
 
-static int brcms_reg_notifier(struct wiphy *wiphy,
-                             struct regulatory_request *request)
+static void brcms_reg_notifier(struct wiphy *wiphy,
+                              struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct brcms_info *wl = hw->priv;
@@ -745,8 +744,6 @@ static int brcms_reg_notifier(struct wiphy *wiphy,
        if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
                wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
                                        brcms_c_japan_ccode(request->alpha2));
-
-       return 0;
 }
 
 void brcms_c_regd_init(struct brcms_c_info *wlc)
index 0f71d1d4339dc38ccfdd89428fdc4a62bb5b7bd9..7fc49ca3f59793a7d5aa9d900266c288ab8c0c59 100644 (file)
@@ -362,8 +362,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                return -EOPNOTSUPP;
        }
 
+       spin_lock_bh(&wl->lock);
+       memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr));
        wl->mute_tx = false;
        brcms_c_mute(wl->wlc, false);
+       spin_unlock_bh(&wl->lock);
 
        return 0;
 }
@@ -668,7 +671,9 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
 
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                spin_lock_bh(&wl->lock);
                brcms_c_ampdu_flush(wl->wlc, sta, tid);
                spin_unlock_bh(&wl->lock);
index 17594de4199ef58a30488e2c7579ec02c521d9ea..c26992a60e6c17ff2cbe0c84ed63527ab9bb1198 100644 (file)
@@ -2473,6 +2473,7 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
 static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
 {
        static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+       u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr;
 
        if (mute_tx) {
                /* suspend tx fifos */
@@ -2482,8 +2483,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
                brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
 
                /* zero the address match register so we do not send ACKs */
-               brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
-                                      null_ether_addr);
+               brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr);
        } else {
                /* resume tx fifos */
                brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
@@ -2492,8 +2492,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
                brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
 
                /* Restore address */
-               brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
-                                      wlc_hw->etheraddr);
+               brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr);
        }
 
        wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
@@ -7633,7 +7632,7 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
 
        uint n = 0;
        uint bound_limit = bound ? RXBND : -1;
-       bool morepending;
+       bool morepending = false;
 
        skb_queue_head_init(&recv_frames);
 
index 51c79c7239b7c12bd4888036e3a93e9673d0c017..3a3d73699f83aad95431e224e7861c0a19a1a069 100644 (file)
@@ -36,7 +36,6 @@
 
 /* structure to store per-tid state for the ampdu initiator */
 struct scb_ampdu_tid_ini {
-       u8 tx_in_transit; /* number of pending mpdus in transit in driver */
        u8 tid;           /* initiator tid for easy lookup */
        /* tx retry count; indexed by seq modulo */
        u8 txretry[AMPDU_TX_BA_MAX_WSIZE];
index 844f201b7b70080b19c4e7ae70bc31f375214a7c..3e824b8fa83dcef94f59695110a72ffd2dfe7533 100644 (file)
@@ -11327,7 +11327,6 @@ static int ipw_up(struct ipw_priv *priv)
                if (!(priv->config & CFG_CUSTOM_MAC))
                        eeprom_parse_mac(priv, priv->mac_addr);
                memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
-               memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN);
 
                ipw_set_geo(priv);
 
index 3726cd6fcd754812d65cb38d89782e96aace0de8..050ce7c70d74653e336fb15144860d89bff6117e 100644 (file)
@@ -3474,6 +3474,7 @@ struct ieee80211_ops il3945_mac_ops = {
        .sta_add = il3945_mac_sta_add,
        .sta_remove = il_mac_sta_remove,
        .tx_last_beacon = il_mac_tx_last_beacon,
+       .flush = il_mac_flush,
 };
 
 static int
@@ -3548,7 +3549,8 @@ il3945_setup_mac(struct il_priv *il)
        hw->vif_data_size = sizeof(struct il_vif_priv);
 
        /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT;
+       hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
+                   IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
        hw->wiphy->interface_modes =
            BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
@@ -3557,6 +3559,8 @@ il3945_setup_mac(struct il_priv *il)
            WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
            WIPHY_FLAG_IBSS_RSN;
 
+       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
        /* we create the 802.11 header and a zero-length SSID element */
        hw->wiphy->max_scan_ie_len = IL3945_MAX_PROBE_REQUEST - 24 - 2;
index c3fbf6717564a3295ea2a87ecdc669e80d2e9d89..f1dc040065646c5ec9d15068a084ff22d00eb656 100644 (file)
@@ -5712,8 +5712,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
        hw->flags =
            IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
            IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT |
-           IEEE80211_HW_REPORTS_TX_ACK_STATUS;
-
+           IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
+           IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
        if (il->cfg->sku & IL_SKU_N)
                hw->flags |=
                    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
@@ -5968,7 +5968,9 @@ il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                D_HT("start Tx\n");
                ret = il4965_tx_agg_start(il, vif, sta, tid, ssn);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                D_HT("stop Tx\n");
                ret = il4965_tx_agg_stop(il, vif, sta, tid);
                if (test_bit(S_EXIT_PENDING, &il->status))
@@ -6306,6 +6308,7 @@ const struct ieee80211_ops il4965_mac_ops = {
        .sta_remove = il_mac_sta_remove,
        .channel_switch = il4965_mac_channel_switch,
        .tx_last_beacon = il_mac_tx_last_beacon,
+       .flush = il_mac_flush,
 };
 
 static int
@@ -6553,6 +6556,7 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        il4965_prepare_card_hw(il);
        if (!il->hw_ready) {
                IL_WARN("Failed, HW not ready\n");
+               err = -EIO;
                goto out_iounmap;
        }
 
index 90b8970eadf0fa7c296be194c2d18ef9266b1043..1f598604a79c1215da9bd612fbe231f3cd4cfb05 100644 (file)
@@ -4700,6 +4700,42 @@ out:
 }
 EXPORT_SYMBOL(il_mac_change_interface);
 
+void
+il_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+       struct il_priv *il = hw->priv;
+       unsigned long timeout = jiffies + msecs_to_jiffies(500);
+       int i;
+
+       mutex_lock(&il->mutex);
+       D_MAC80211("enter\n");
+
+       if (il->txq == NULL)
+               goto out;
+
+       for (i = 0; i < il->hw_params.max_txq_num; i++) {
+               struct il_queue *q;
+
+               if (i == il->cmd_queue)
+                       continue;
+
+               q = &il->txq[i].q;
+               if (q->read_ptr == q->write_ptr)
+                       continue;
+
+               if (time_after(jiffies, timeout)) {
+                       IL_ERR("Failed to flush queue %d\n", q->id);
+                       break;
+               }
+
+               msleep(20);
+       }
+out:
+       D_MAC80211("leave\n");
+       mutex_unlock(&il->mutex);
+}
+EXPORT_SYMBOL(il_mac_flush);
+
 /*
  * On every watchdog tick we check (latest) time stamp. If it does not
  * change during timeout period and queue is not empty we reset firmware.
index a9a569f432fb3517d5421ea1c4d43cdd96a4d816..37fe553b25e0e86e8b0f772ba08da42d8808b920 100644 (file)
@@ -1723,6 +1723,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif);
 int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            enum nl80211_iftype newtype, bool newp2p);
+void il_mac_flush(struct ieee80211_hw *hw, bool drop);
 int il_alloc_txq_mem(struct il_priv *il);
 void il_free_txq_mem(struct il_priv *il);
 
index 71ab76b2b39d18da16518e99b5d36ab90ac87042..0ca99c13f7f2a9f76944b5b549856da3771bcfe4 100644 (file)
@@ -3695,7 +3695,7 @@ struct iwl_bt_uart_msg {
        u8 frame5;
        u8 frame6;
        u8 frame7;
-} __attribute__((packed));
+} __packed;
 
 struct iwl_bt_coex_profile_notif {
        struct iwl_bt_uart_msg last_bt_uart_msg;
@@ -3703,7 +3703,7 @@ struct iwl_bt_coex_profile_notif {
        u8 bt_traffic_load; /* 0 .. 3? */
        u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
        u8 reserved;
-} __attribute__((packed));
+} __packed;
 
 #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS        0
 #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK        0x1
@@ -3752,7 +3752,7 @@ enum bt_coex_prio_table_priorities {
 
 struct iwl_bt_coex_prio_table_cmd {
        u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
-} __attribute__((packed));
+} __packed;
 
 #define IWL_BT_COEX_ENV_CLOSE  0
 #define IWL_BT_COEX_ENV_OPEN   1
@@ -3764,7 +3764,7 @@ struct iwl_bt_coex_prot_env_cmd {
        u8 action; /* 0 = closed, 1 = open */
        u8 type; /* 0 .. 15 */
        u8 reserved[2];
-} __attribute__((packed));
+} __packed;
 
 /*
  * REPLY_D3_CONFIG
index 5b9533eef54dd7bb173c250ac0eb42666ff06e87..72c74af38138290a370f9c65c82a104c6ba0609f 100644 (file)
@@ -157,7 +157,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
        sram = priv->dbgfs_sram_offset & ~0x3;
 
        /* read the first u32 from sram */
-       val = iwl_read_targ_mem(priv->trans, sram);
+       val = iwl_trans_read_mem32(priv->trans, sram);
 
        for (; len; len--) {
                /* put the address at the start of every line */
@@ -176,7 +176,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
                if (++offset == 4) {
                        sram += 4;
                        offset = 0;
-                       val = iwl_read_targ_mem(priv->trans, sram);
+                       val = iwl_trans_read_mem32(priv->trans, sram);
                }
 
                /* put in extra spaces and split lines for human readability */
index bf479f709091d6954e779c079c379e48a578c2f5..844a17f99a186c6ed20e0c71d94465839cddd914 100644 (file)
@@ -69,7 +69,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = {
 /* Set led register off */
 void iwlagn_led_enable(struct iwl_priv *priv)
 {
-       iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+       iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
 }
 
 /*
index 3163e0f38c25109a3c5f5a2e7c71f39f37b40eda..0353e1c0670d8b087a959b2ccec4d107c9f30309 100644 (file)
@@ -206,7 +206,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
 
 #ifdef CONFIG_PM_SLEEP
        if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
-           priv->trans->ops->wowlan_suspend &&
+           priv->trans->ops->d3_suspend &&
+           priv->trans->ops->d3_resume &&
            device_can_wakeup(priv->trans->dev)) {
                hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
                                          WIPHY_WOWLAN_DISCONNECT |
@@ -426,7 +427,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
        if (ret)
                goto error;
 
-       iwl_trans_wowlan_suspend(priv->trans);
+       iwl_trans_d3_suspend(priv->trans);
 
        goto out;
 
@@ -459,11 +460,11 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        base = priv->device_pointers.error_event_table;
        if (iwlagn_hw_valid_rtc_data_addr(base)) {
                spin_lock_irqsave(&priv->trans->reg_lock, flags);
-               ret = iwl_grab_nic_access_silent(priv->trans);
-               if (likely(ret == 0)) {
+               if (iwl_trans_grab_nic_access(priv->trans, true)) {
                        iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
                        status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-                       iwl_release_nic_access(priv->trans);
+                       iwl_trans_release_nic_access(priv->trans);
+                       ret = 0;
                }
                spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
 
@@ -479,7 +480,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
                        }
 
                        if (priv->wowlan_sram)
-                               _iwl_read_targ_mem_dwords(
+                               iwl_trans_read_mem(
                                      priv->trans, 0x800000,
                                      priv->wowlan_sram,
                                      img->sec[IWL_UCODE_SECTION_DATA].len / 4);
@@ -520,9 +521,6 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
-       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
        if (iwlagn_tx_skb(priv, control->sta, skb))
                ieee80211_free_txskb(hw, skb);
 }
@@ -679,7 +677,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                IWL_DEBUG_HT(priv, "start Tx\n");
                ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                IWL_DEBUG_HT(priv, "stop Tx\n");
                ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
                if ((ret == 0) && (priv->agg_tids_count > 0)) {
index faa05932efae92e80c322b4a28d606da7cb9808b..a64f361e341cb0028baaa5a1533d4210f8d03f69 100644 (file)
@@ -354,7 +354,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
 
        /* Make sure device is powered up for SRAM reads */
        spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
-       if (unlikely(!iwl_grab_nic_access(priv->trans))) {
+       if (!iwl_trans_grab_nic_access(priv->trans, false)) {
                spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
                return;
        }
@@ -388,7 +388,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
                }
        }
        /* Allow device to power down */
-       iwl_release_nic_access(priv->trans);
+       iwl_trans_release_nic_access(priv->trans);
        spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
 }
 
@@ -408,7 +408,8 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
 
        base = priv->device_pointers.log_event_table;
        if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read));
+               iwl_trans_read_mem_bytes(priv->trans, base,
+                                        &read, sizeof(read));
                capacity = read.capacity;
                mode = read.mode;
                num_wraps = read.wrap_counter;
@@ -1627,7 +1628,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
        }
 
        /*TODO: Update dbgfs with ISR error stats obtained below */
-       iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table));
+       iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
 
        if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
                IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -1717,7 +1718,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
 
        /* Make sure device is powered up for SRAM reads */
        spin_lock_irqsave(&trans->reg_lock, reg_flags);
-       if (unlikely(!iwl_grab_nic_access(trans)))
+       if (!iwl_trans_grab_nic_access(trans, false))
                goto out_unlock;
 
        /* Set starting address; reads will auto-increment */
@@ -1756,7 +1757,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
        }
 
        /* Allow device to power down */
-       iwl_release_nic_access(trans);
+       iwl_trans_release_nic_access(trans);
 out_unlock:
        spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
        return pos;
@@ -1835,10 +1836,10 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        }
 
        /* event log header */
-       capacity = iwl_read_targ_mem(trans, base);
-       mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
-       num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
-       next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
+       capacity = iwl_trans_read_mem32(trans, base);
+       mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32)));
+       num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32)));
+       next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32)));
 
        if (capacity > logsize) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
index eb864433e59de0ec749a3693d950c4065f2d6b32..b28cfc8553d749a4ca156f7a49849c0c2da28365 100644 (file)
@@ -186,8 +186,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
                }
                iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
                spin_lock_irqsave(&priv->trans->reg_lock, flags);
-               if (likely(iwl_grab_nic_access(priv->trans)))
-                       iwl_release_nic_access(priv->trans);
+               if (iwl_trans_grab_nic_access(priv->trans, false))
+                       iwl_trans_release_nic_access(priv->trans);
                spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
 
                /* Reschedule the ct_kill timer to occur in
index 31534f7c05488ba38d4c65c7ce0209a43712fd51..6b01fc1959406016d761699bd298c5628719d174 100644 (file)
@@ -231,13 +231,11 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
                memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
                if (info->flags & IEEE80211_TX_CTL_AMPDU)
                        tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-               IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
                break;
 
        case WLAN_CIPHER_SUITE_TKIP:
                tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
                ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
-               IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
                break;
 
        case WLAN_CIPHER_SUITE_WEP104:
@@ -355,8 +353,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
                }
        }
 
-       IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
-
        if (sta)
                sta_priv = (void *)sta->drv_priv;
 
@@ -472,6 +468,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
        WARN_ON_ONCE(is_agg &&
                     priv->queue_to_mac80211[txq_id] != info->hw_queue);
 
+       IWL_DEBUG_TX(priv, "TX to [%d|%d] Q:%d - seq: 0x%x\n", sta_id, tid,
+                    txq_id, seq_number);
+
        if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
                goto drop_unlock_sta;
 
@@ -541,9 +540,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
        spin_lock_bh(&priv->sta_lock);
 
        tid_data = &priv->tid_data[sta_id][tid];
-       txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+       txq_id = tid_data->agg.txq_id;
 
-       switch (priv->tid_data[sta_id][tid].agg.state) {
+       switch (tid_data->agg.state) {
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
                /*
                * This can happen if the peer stops aggregation
@@ -563,9 +562,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
        case IWL_AGG_ON:
                break;
        default:
-               IWL_WARN(priv, "Stopping AGG while state not ON "
-                        "or starting for %d on %d (%d)\n", sta_id, tid,
-                        priv->tid_data[sta_id][tid].agg.state);
+               IWL_WARN(priv,
+                        "Stopping AGG while state not ON or starting for %d on %d (%d)\n",
+                        sta_id, tid, tid_data->agg.state);
                spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
@@ -578,12 +577,11 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                        "stopping AGG on STA/TID %d/%d but hwq %d not used\n",
                        sta_id, tid, txq_id);
        } else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
-               IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
-                                   "next_recl = %d\n",
+               IWL_DEBUG_TX_QUEUES(priv,
+                                   "Can't proceed: ssn %d, next_recl = %d\n",
                                    tid_data->agg.ssn,
                                    tid_data->next_reclaimed);
-               priv->tid_data[sta_id][tid].agg.state =
-                       IWL_EMPTYING_HW_QUEUE_DELBA;
+               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA;
                spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
@@ -591,8 +589,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
        IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
                            tid_data->agg.ssn);
 turn_off:
-       agg_state = priv->tid_data[sta_id][tid].agg.state;
-       priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
+       agg_state = tid_data->agg.state;
+       tid_data->agg.state = IWL_AGG_OFF;
 
        spin_unlock_bh(&priv->sta_lock);
 
@@ -954,12 +952,6 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
                if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
                              AGG_TX_STATE_ABORT_MSK))
                        continue;
-
-               IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
-                                  "try-count (0x%08x)\n",
-                                  iwl_get_agg_tx_fail_reason(fstatus),
-                                  fstatus & AGG_TX_STATUS_MSK,
-                                  fstatus & AGG_TX_TRY_MSK);
        }
 }
 
@@ -1225,16 +1217,27 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                                           next_reclaimed);
                }
 
-               WARN_ON(!is_agg && freed != 1);
+               if (!is_agg && freed != 1)
+                       IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed);
 
                /*
                 * An offchannel frame can be send only on the AUX queue, where
                 * there is no aggregation (and reordering) so it only is single
                 * skb is expected to be processed.
                 */
-               WARN_ON(is_offchannel_skb && freed != 1);
+               if (is_offchannel_skb && freed != 1)
+                       IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed);
        }
 
+       IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id,
+                          iwl_get_tx_fail_reason(status), status);
+
+       IWL_DEBUG_TX_REPLY(priv,
+                          "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n",
+                          le32_to_cpu(tx_resp->rate_n_flags),
+                          tx_resp->failure_frame, SEQ_TO_INDEX(sequence), ssn,
+                          le16_to_cpu(tx_resp->seq_ctl));
+
        iwl_check_abort_status(priv, tx_resp->frame_count, status);
        spin_unlock(&priv->sta_lock);
 
index c6467e5554f5c2992c27a0871b418680225dfdc6..ebec13a3329f00c2b95ce824930a0afcbaac9696 100644 (file)
@@ -286,89 +286,6 @@ static int iwl_alive_notify(struct iwl_priv *priv)
        return iwl_send_calib_results(priv);
 }
 
-
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- *   using sample data 100 bytes apart.  If these sample points are good,
- *   it's a pretty good bet that everything between them is good, too.
- */
-static int iwl_verify_sec_sparse(struct iwl_priv *priv,
-                                 const struct fw_desc *fw_desc)
-{
-       __le32 *image = (__le32 *)fw_desc->data;
-       u32 len = fw_desc->len;
-       u32 val;
-       u32 i;
-
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
-       for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
-               /* read data comes through single port, auto-incr addr */
-               /* NOTE: Use the debugless read so we don't flood kernel log
-                * if IWL_DL_IO is set */
-               iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
-                       i + fw_desc->offset);
-               val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-               if (val != le32_to_cpu(*image))
-                       return -EIO;
-       }
-
-       return 0;
-}
-
-static void iwl_print_mismatch_sec(struct iwl_priv *priv,
-                                   const struct fw_desc *fw_desc)
-{
-       __le32 *image = (__le32 *)fw_desc->data;
-       u32 len = fw_desc->len;
-       u32 val;
-       u32 offs;
-       int errors = 0;
-
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
-       iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
-                               fw_desc->offset);
-
-       for (offs = 0;
-            offs < len && errors < 20;
-            offs += sizeof(u32), image++) {
-               /* read data comes through single port, auto-incr addr */
-               val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-               if (val != le32_to_cpu(*image)) {
-                       IWL_ERR(priv, "uCode INST section at "
-                               "offset 0x%x, is 0x%x, s/b 0x%x\n",
-                               offs, val, le32_to_cpu(*image));
-                       errors++;
-               }
-       }
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- *    and verify its contents
- */
-static int iwl_verify_ucode(struct iwl_priv *priv,
-                           enum iwl_ucode_type ucode_type)
-{
-       const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
-
-       if (!img) {
-               IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
-               return -EINVAL;
-       }
-
-       if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
-               IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
-               return 0;
-       }
-
-       IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
-
-       iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
-       return -EIO;
-}
-
 struct iwl_alive_data {
        bool valid;
        u8 subtype;
@@ -426,7 +343,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
                                   alive_cmd, ARRAY_SIZE(alive_cmd),
                                   iwl_alive_fn, &alive_data);
 
-       ret = iwl_trans_start_fw(priv->trans, fw);
+       ret = iwl_trans_start_fw(priv->trans, fw, false);
        if (ret) {
                priv->cur_ucode = old_type;
                iwl_remove_notification(&priv->notif_wait, &alive_wait);
@@ -450,18 +367,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
                return -EIO;
        }
 
-       /*
-        * This step takes a long time (60-80ms!!) and
-        * WoWLAN image should be loaded quickly, so
-        * skip it for WoWLAN.
-        */
        if (ucode_type != IWL_UCODE_WOWLAN) {
-               ret = iwl_verify_ucode(priv, ucode_type);
-               if (ret) {
-                       priv->cur_ucode = old_type;
-                       return ret;
-               }
-
                /* delay a bit to give rfkill time to run */
                msleep(5);
        }
index 34a5287dfc2f6d1c366e6555a14ee284dad8bd5e..b419a1efac0ab1e2505e46d48be032932a857d5d 100644 (file)
 
 /* LED */
 #define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
-#define CSR_LED_REG_TRUN_ON (0x78)
-#define CSR_LED_REG_TRUN_OFF (0x38)
+#define CSR_LED_REG_TURN_ON (0x60)
+#define CSR_LED_REG_TURN_OFF (0x20)
 
 /* ANA_PLL */
 #define CSR50_ANA_PLL_CFG_VAL        (0x00880300)
index ec48563d3c6ad3e05f652ce936ff5fabc8cb2b2b..c646a90b725e22436f2268a16a067beaf5698ada 100644 (file)
@@ -225,6 +225,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG  (FH_MEM_RSCSR_CHNL0 + 0x008)
 #define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
 
+#define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x00c)
+#define FH_RSCSR_CHNL0_RDPTR           FW_RSCSR_CHNL0_RXDCB_RDPTR_REG
 
 /**
  * Rx Config/Status Registers (RCSR)
@@ -257,6 +259,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)
 
 #define FH_MEM_RCSR_CHNL0_CONFIG_REG   (FH_MEM_RCSR_CHNL0)
+#define FH_MEM_RCSR_CHNL0_RBDCB_WPTR   (FH_MEM_RCSR_CHNL0 + 0x8)
+#define FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ (FH_MEM_RCSR_CHNL0 + 0x10)
 
 #define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */
 #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK   (0x00001000) /* bits 12 */
index d1a86b66bc51ee6fab8e797e8aa458b9db3812ea..715291eb7f8e8070d576a5e91341a354a56a1c34 100644 (file)
@@ -157,7 +157,7 @@ struct fw_img {
 struct iwl_fw {
        u32 ucode_ver;
 
-       char fw_version[ETHTOOL_BUSINFO_LEN];
+       char fw_version[ETHTOOL_FWVERS_LEN];
 
        /* ucode images */
        struct fw_img img[IWL_UCODE_TYPE_MAX];
index cdaff9572059bd162beb8e050a0215d3f632ebcd..bff3ac96c00bceb380d7780b263d66db384ef34d 100644 (file)
 
 #define IWL_POLL_INTERVAL 10   /* microseconds */
 
-static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
+void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
 {
        iwl_write32(trans, reg, iwl_read32(trans, reg) | mask);
 }
 
-static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
+void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
 {
        iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask);
 }
@@ -99,86 +99,16 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 }
 EXPORT_SYMBOL_GPL(iwl_poll_bit);
 
-int iwl_grab_nic_access_silent(struct iwl_trans *trans)
-{
-       int ret;
-
-       lockdep_assert_held(&trans->reg_lock);
-
-       /* this bit wakes up the NIC */
-       __iwl_set_bit(trans, CSR_GP_CNTRL,
-                     CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-       /*
-        * These bits say the device is running, and should keep running for
-        * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
-        * but they do not indicate that embedded SRAM is restored yet;
-        * 3945 and 4965 have volatile SRAM, and must save/restore contents
-        * to/from host DRAM when sleeping/waking for power-saving.
-        * Each direction takes approximately 1/4 millisecond; with this
-        * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
-        * series of register accesses are expected (e.g. reading Event Log),
-        * to keep device from sleeping.
-        *
-        * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
-        * SRAM is okay/restored.  We don't check that here because this call
-        * is just for hardware register access; but GP1 MAC_SLEEP check is a
-        * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
-        *
-        * 5000 series and later (including 1000 series) have non-volatile SRAM,
-        * and do not save/restore SRAM when power cycling.
-        */
-       ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
-                          CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
-                          (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
-                           CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
-       if (ret < 0) {
-               iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
-               return -EIO;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
-
-bool iwl_grab_nic_access(struct iwl_trans *trans)
-{
-       int ret = iwl_grab_nic_access_silent(trans);
-       if (unlikely(ret)) {
-               u32 val = iwl_read32(trans, CSR_GP_CNTRL);
-               WARN_ONCE(1, "Timeout waiting for hardware access "
-                            "(CSR_GP_CNTRL 0x%08x)\n", val);
-               return false;
-       }
-
-       return true;
-}
-EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
-
-void iwl_release_nic_access(struct iwl_trans *trans)
-{
-       lockdep_assert_held(&trans->reg_lock);
-       __iwl_clear_bit(trans, CSR_GP_CNTRL,
-                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-       /*
-        * Above we read the CSR_GP_CNTRL register, which will flush
-        * any previous writes, but we need the write that clears the
-        * MAC_ACCESS_REQ bit to be performed before any other writes
-        * scheduled on different CPUs (after we drop reg_lock).
-        */
-       mmiowb();
-}
-EXPORT_SYMBOL_GPL(iwl_release_nic_access);
-
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 {
-       u32 value;
+       u32 value = 0x5a5a5a5a;
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       iwl_grab_nic_access(trans);
-       value = iwl_read32(trans, reg);
-       iwl_release_nic_access(trans);
+       if (iwl_trans_grab_nic_access(trans, false)) {
+               value = iwl_read32(trans, reg);
+               iwl_trans_release_nic_access(trans);
+       }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 
        return value;
@@ -190,9 +120,9 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (likely(iwl_grab_nic_access(trans))) {
+       if (iwl_trans_grab_nic_access(trans, false)) {
                iwl_write32(trans, reg, value);
-               iwl_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -230,12 +160,13 @@ static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
 u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
 {
        unsigned long flags;
-       u32 val;
+       u32 val = 0x5a5a5a5a;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       iwl_grab_nic_access(trans);
-       val = __iwl_read_prph(trans, ofs);
-       iwl_release_nic_access(trans);
+       if (iwl_trans_grab_nic_access(trans, false)) {
+               val = __iwl_read_prph(trans, ofs);
+               iwl_trans_release_nic_access(trans);
+       }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
        return val;
 }
@@ -246,9 +177,9 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (likely(iwl_grab_nic_access(trans))) {
+       if (iwl_trans_grab_nic_access(trans, false)) {
                __iwl_write_prph(trans, ofs, val);
-               iwl_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -259,10 +190,10 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (likely(iwl_grab_nic_access(trans))) {
+       if (iwl_trans_grab_nic_access(trans, false)) {
                __iwl_write_prph(trans, ofs,
                                 __iwl_read_prph(trans, ofs) | mask);
-               iwl_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -274,10 +205,10 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
        unsigned long flags;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (likely(iwl_grab_nic_access(trans))) {
+       if (iwl_trans_grab_nic_access(trans, false)) {
                __iwl_write_prph(trans, ofs,
                                 (__iwl_read_prph(trans, ofs) & mask) | bits);
-               iwl_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
@@ -289,66 +220,11 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
        u32 val;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
-       if (likely(iwl_grab_nic_access(trans))) {
+       if (iwl_trans_grab_nic_access(trans, false)) {
                val = __iwl_read_prph(trans, ofs);
                __iwl_write_prph(trans, ofs, (val & ~mask));
-               iwl_release_nic_access(trans);
+               iwl_trans_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
-
-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-                              void *buf, int dwords)
-{
-       unsigned long flags;
-       int offs;
-       u32 *vals = buf;
-
-       spin_lock_irqsave(&trans->reg_lock, flags);
-       if (likely(iwl_grab_nic_access(trans))) {
-               iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
-               for (offs = 0; offs < dwords; offs++)
-                       vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-               iwl_release_nic_access(trans);
-       }
-       spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
-{
-       u32 value;
-
-       _iwl_read_targ_mem_dwords(trans, addr, &value, 1);
-
-       return value;
-}
-EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-                              const void *buf, int dwords)
-{
-       unsigned long flags;
-       int offs, result = 0;
-       const u32 *vals = buf;
-
-       spin_lock_irqsave(&trans->reg_lock, flags);
-       if (likely(iwl_grab_nic_access(trans))) {
-               iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
-               for (offs = 0; offs < dwords; offs++)
-                       iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
-               iwl_release_nic_access(trans);
-       } else
-               result = -EBUSY;
-       spin_unlock_irqrestore(&trans->reg_lock, flags);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords);
-
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
-{
-       return _iwl_write_targ_mem_dwords(trans, addr, &val, 1);
-}
-EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
index 48dc753e3742aab857af7f88617b81206dc163cc..dc478068596bc65f87cc617ce01091e08cbfae1b 100644 (file)
@@ -53,6 +53,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
 
 void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
 void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
+void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
+void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
 
 void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
 
@@ -61,10 +63,6 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
                        int timeout);
 
-int iwl_grab_nic_access_silent(struct iwl_trans *trans);
-bool iwl_grab_nic_access(struct iwl_trans *trans);
-void iwl_release_nic_access(struct iwl_trans *trans);
-
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
 void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
 
@@ -76,19 +74,4 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
                            u32 bits, u32 mask);
 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
 
-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-                              void *buf, int dwords);
-
-#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize)     \
-       do {                                                    \
-               BUILD_BUG_ON((bufsize) % sizeof(u32));          \
-               _iwl_read_targ_mem_dwords(trans, addr, buf,     \
-                                         (bufsize) / sizeof(u32));\
-       } while (0)
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-                              const void *buf, int dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
 #endif
index 81e8c7126d7293016d91e0a787d9a9991fea08ac..1a226114fe73c9669273a5e28468d9bf6e625b51 100644 (file)
@@ -467,18 +467,20 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
        if (IWL_ABS_PRPH_START <= addr &&
            addr < IWL_ABS_PRPH_START + PRPH_END) {
                        spin_lock_irqsave(&trans->reg_lock, flags);
-                       iwl_grab_nic_access(trans);
+                       if (!iwl_trans_grab_nic_access(trans, false)) {
+                               spin_unlock_irqrestore(&trans->reg_lock, flags);
+                               return -EIO;
+                       }
                        iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
                                    addr | (3 << 24));
                        for (i = 0; i < size; i += 4)
                                *(u32 *)(tst->mem.addr + i) =
                                        iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
-                       iwl_release_nic_access(trans);
+                       iwl_trans_release_nic_access(trans);
                        spin_unlock_irqrestore(&trans->reg_lock, flags);
        } else { /* target memory (SRAM) */
-               _iwl_read_targ_mem_dwords(trans, addr,
-                                         tst->mem.addr,
-                                         tst->mem.size / 4);
+               iwl_trans_read_mem(trans, addr, tst->mem.addr,
+                                  tst->mem.size / 4);
        }
 
        tst->mem.nchunks =
@@ -501,28 +503,31 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
 
        if (IWL_ABS_PRPH_START <= addr &&
            addr < IWL_ABS_PRPH_START + PRPH_END) {
-                       /* Periphery writes can be 1-3 bytes long, or DWORDs */
-                       if (size < 4) {
-                               memcpy(&val, buf, size);
-                               spin_lock_irqsave(&trans->reg_lock, flags);
-                               iwl_grab_nic_access(trans);
-                               iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
-                                           (addr & 0x0000FFFF) |
-                                           ((size - 1) << 24));
-                               iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
-                               iwl_release_nic_access(trans);
-                               /* needed after consecutive writes w/o read */
-                               mmiowb();
+               /* Periphery writes can be 1-3 bytes long, or DWORDs */
+               if (size < 4) {
+                       memcpy(&val, buf, size);
+                       spin_lock_irqsave(&trans->reg_lock, flags);
+                       if (!iwl_trans_grab_nic_access(trans, false)) {
                                spin_unlock_irqrestore(&trans->reg_lock, flags);
-                       } else {
-                               if (size % 4)
-                                       return -EINVAL;
-                               for (i = 0; i < size; i += 4)
-                                       iwl_write_prph(trans, addr+i,
-                                                      *(u32 *)(buf+i));
+                                       return -EIO;
                        }
+                       iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
+                                   (addr & 0x0000FFFF) |
+                                   ((size - 1) << 24));
+                       iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
+                       iwl_trans_release_nic_access(trans);
+                       /* needed after consecutive writes w/o read */
+                       mmiowb();
+                       spin_unlock_irqrestore(&trans->reg_lock, flags);
+               } else {
+                       if (size % 4)
+                               return -EINVAL;
+                       for (i = 0; i < size; i += 4)
+                               iwl_write_prph(trans, addr+i,
+                                              *(u32 *)(buf+i));
+               }
        } else if (iwl_test_valid_hw_addr(tst, addr)) {
-               _iwl_write_targ_mem_dwords(trans, addr, buf, size / 4);
+               iwl_trans_write_mem(trans, addr, buf, size / 4);
        } else {
                return -EINVAL;
        }
index b76532e238c166f9c5095ac1ab5564c1e56a8aa0..0f85eb3058787614d2882d67c58fb6b17b214712 100644 (file)
@@ -307,6 +307,16 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
 #define IWL_MAX_TID_COUNT      8
 #define IWL_FRAME_LIMIT        64
 
+/**
+ * enum iwl_wowlan_status - WoWLAN image/device status
+ * @IWL_D3_STATUS_ALIVE: firmware is still running after resume
+ * @IWL_D3_STATUS_RESET: device was reset while suspended
+ */
+enum iwl_d3_status {
+       IWL_D3_STATUS_ALIVE,
+       IWL_D3_STATUS_RESET,
+};
+
 /**
  * struct iwl_trans_config - transport configuration
  *
@@ -321,6 +331,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
  * @n_no_reclaim_cmds: # of commands in list
  * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs,
  *     if unset 4k will be the RX buffer size
+ * @bc_table_dword: set to true if the BC table expects the byte count to be
+ *     in DWORD (as opposed to bytes)
  * @queue_watchdog_timeout: time (in ms) after which queues
  *     are considered stuck and will trigger device restart
  * @command_names: array of command names, must be 256 entries
@@ -335,6 +347,7 @@ struct iwl_trans_config {
        int n_no_reclaim_cmds;
 
        bool rx_buf_size_8k;
+       bool bc_table_dword;
        unsigned int queue_watchdog_timeout;
        const char **command_names;
 };
@@ -360,9 +373,12 @@ struct iwl_trans;
  *     May sleep
  * @stop_device:stops the whole device (embedded CPU put to reset)
  *     May sleep
- * @wowlan_suspend: put the device into the correct mode for WoWLAN during
+ * @d3_suspend: put the device into the correct mode for WoWLAN during
  *     suspend. This is optional, if not implemented WoWLAN will not be
  *     supported. This callback may sleep.
+ * @d3_resume: resume the device after WoWLAN, enabling the opmode to
+ *     talk to the WoWLAN image to get its status. This is optional, if not
+ *     implemented WoWLAN will not be supported. This callback may sleep.
  * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
  *     If RFkill is asserted in the middle of a SYNC host command, it must
  *     return -ERFKILL straight away.
@@ -387,20 +403,27 @@ struct iwl_trans;
  * @read32: read a u32 register at offset ofs from the BAR
  * @read_prph: read a DWORD from a periphery register
  * @write_prph: write a DWORD to a periphery register
+ * @read_mem: read device's SRAM in DWORD
+ * @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory
+ *     will be zeroed.
  * @configure: configure parameters required by the transport layer from
  *     the op_mode. May be called several times before start_fw, can't be
  *     called after that.
  * @set_pmi: set the power pmi state
+ * @grab_nic_access: wake the NIC to be able to access non-HBUS regs
+ * @release_nic_access: let the NIC go to sleep
  */
 struct iwl_trans_ops {
 
        int (*start_hw)(struct iwl_trans *iwl_trans);
        void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
-       int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
+       int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
+                       bool run_in_rfkill);
        void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
        void (*stop_device)(struct iwl_trans *trans);
 
-       void (*wowlan_suspend)(struct iwl_trans *trans);
+       void (*d3_suspend)(struct iwl_trans *trans);
+       int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -424,9 +447,15 @@ struct iwl_trans_ops {
        u32 (*read32)(struct iwl_trans *trans, u32 ofs);
        u32 (*read_prph)(struct iwl_trans *trans, u32 ofs);
        void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val);
+       int (*read_mem)(struct iwl_trans *trans, u32 addr,
+                       void *buf, int dwords);
+       int (*write_mem)(struct iwl_trans *trans, u32 addr,
+                        void *buf, int dwords);
        void (*configure)(struct iwl_trans *trans,
                          const struct iwl_trans_config *trans_cfg);
        void (*set_pmi)(struct iwl_trans *trans, bool state);
+       bool (*grab_nic_access)(struct iwl_trans *trans, bool silent);
+       void (*release_nic_access)(struct iwl_trans *trans);
 };
 
 /**
@@ -528,13 +557,14 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr)
 }
 
 static inline int iwl_trans_start_fw(struct iwl_trans *trans,
-                                    const struct fw_img *fw)
+                                    const struct fw_img *fw,
+                                    bool run_in_rfkill)
 {
        might_sleep();
 
        WARN_ON_ONCE(!trans->rx_mpdu_cmd);
 
-       return trans->ops->start_fw(trans, fw);
+       return trans->ops->start_fw(trans, fw, run_in_rfkill);
 }
 
 static inline void iwl_trans_stop_device(struct iwl_trans *trans)
@@ -546,10 +576,17 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
        trans->state = IWL_TRANS_NO_FW;
 }
 
-static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
+static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
+{
+       might_sleep();
+       trans->ops->d3_suspend(trans);
+}
+
+static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
+                                     enum iwl_d3_status *status)
 {
        might_sleep();
-       trans->ops->wowlan_suspend(trans);
+       return trans->ops->d3_resume(trans, status);
 }
 
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
@@ -636,7 +673,7 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
 }
 
 static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
-                                           struct dentry *dir)
+                                          struct dentry *dir)
 {
        return trans->ops->dbgfs_register(trans, dir);
 }
@@ -679,11 +716,57 @@ static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs,
        return trans->ops->write_prph(trans, ofs, val);
 }
 
+static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
+                                    void *buf, int dwords)
+{
+       return trans->ops->read_mem(trans, addr, buf, dwords);
+}
+
+#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize)                  \
+       do {                                                                  \
+               if (__builtin_constant_p(bufsize))                            \
+                       BUILD_BUG_ON((bufsize) % sizeof(u32));                \
+               iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\
+       } while (0)
+
+static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
+{
+       u32 value;
+
+       if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1)))
+               return 0xa5a5a5a5;
+
+       return value;
+}
+
+static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
+                                     void *buf, int dwords)
+{
+       return trans->ops->write_mem(trans, addr, buf, dwords);
+}
+
+static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
+                                       u32 val)
+{
+       return iwl_trans_write_mem(trans, addr, &val, 1);
+}
+
 static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
 {
        trans->ops->set_pmi(trans, state);
 }
 
+#define iwl_trans_grab_nic_access(trans, silent)       \
+       __cond_lock(nic_access,                         \
+                   likely((trans)->ops->grab_nic_access(trans, silent)))
+
+static inline void __releases(nic_access)
+iwl_trans_release_nic_access(struct iwl_trans *trans)
+{
+       trans->ops->release_nic_access(trans);
+       __release(nic_access);
+}
+
 /*****************************************************
 * driver (transport) register/unregister functions
 ******************************************************/
index d91d2e8c62f53e687a7eb4ae513a36035c495e78..20735a008cab0de577c1719ef2f019d3a3190a33 100644 (file)
@@ -222,8 +222,6 @@ struct iwl_txq {
  * @rx_replenish: work that will be called when buffers need to be allocated
  * @drv - pointer to iwl_drv
  * @trans: pointer to the generic transport area
- * @irq - the irq number for the device
- * @irq_requested: true when the irq has been requested
  * @scd_base_addr: scheduler sram base address in SRAM
  * @scd_bc_tbls: pointer to the byte count table of the scheduler
  * @kw: keep warm address
@@ -234,6 +232,7 @@ struct iwl_txq {
  * @status - transport specific status flags
  * @cmd_queue - command queue number
  * @rx_buf_size_8k: 8 kB RX buffer size
+ * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
  * @rx_page_order: page order for receive buffer size
  * @wd_timeout: queue watchdog timeout (jiffies)
  */
@@ -249,11 +248,9 @@ struct iwl_trans_pcie {
        int ict_index;
        u32 inta;
        bool use_ict;
-       bool irq_requested;
        struct tasklet_struct irq_tasklet;
        struct isr_statistics isr_stats;
 
-       unsigned int irq;
        spinlock_t irq_lock;
        u32 inta_mask;
        u32 scd_base_addr;
@@ -279,6 +276,7 @@ struct iwl_trans_pcie {
        u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
 
        bool rx_buf_size_8k;
+       bool bc_table_dword;
        u32 rx_page_order;
 
        const char **command_names;
@@ -359,6 +357,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
                            struct iwl_rx_cmd_buffer *rxb, int handler_status);
 void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
                            struct sk_buff_head *skbs);
+void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
+
 /*****************************************************
 * Error handling
 ******************************************************/
index 8389cd38338ba70766561d13c35591e1073faca6..4e6591d24e61be2ccccbdf0dd2d08ac1d0448aa3 100644 (file)
@@ -436,7 +436,7 @@ static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
 err_rb_stts:
        dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
                          rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd_dma = 0;
        rxq->bd = NULL;
 err_bd:
        return -ENOMEM;
@@ -455,6 +455,10 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
 
        /* Stop Rx DMA */
        iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       /* reset and flush pointers */
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
+       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
 
        /* Reset driver's Rx queue write index */
        iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
@@ -491,7 +495,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-
        int i, err;
        unsigned long flags;
 
@@ -518,6 +521,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        rxq->read = rxq->write = 0;
        rxq->write_actual = 0;
        rxq->free_count = 0;
+       memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
        spin_unlock_irqrestore(&rxq->lock, flags);
 
        iwl_pcie_rx_replenish(trans);
@@ -545,13 +549,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
                return;
        }
 
+       cancel_work_sync(&trans_pcie->rx_replenish);
+
        spin_lock_irqsave(&rxq->lock, flags);
        iwl_pcie_rxq_free_rbs(trans);
        spin_unlock_irqrestore(&rxq->lock, flags);
 
        dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
                          rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd_dma = 0;
        rxq->bd = NULL;
 
        if (rxq->rb_stts)
@@ -560,7 +566,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
                                  rxq->rb_stts, rxq->rb_stts_dma);
        else
                IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-       memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+       rxq->rb_stts_dma = 0;
        rxq->rb_stts = NULL;
 }
 
index 35708b959ad6e563a38d29f1bd75c51e87c9c2c8..c57641eb83d55622646f9d581b66e11f0d5fa22e 100644 (file)
 #include "iwl-agn-hw.h"
 #include "internal.h"
 
-static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans)
+static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
 {
-/*
- * (for documentation purposes)
- * to set power to V_AUX, do:
-
-               if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
-                       iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-                                              APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
-                                              ~APMG_PS_CTRL_MSK_PWR_SRC);
- */
-
-       iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-                              APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
-                              ~APMG_PS_CTRL_MSK_PWR_SRC);
+       if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
+               iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+                                      APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+                                      ~APMG_PS_CTRL_MSK_PWR_SRC);
+       else
+               iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+                                      APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+                                      ~APMG_PS_CTRL_MSK_PWR_SRC);
 }
 
 /* PCI registers */
@@ -259,7 +254,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
 
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
-       iwl_pcie_set_pwr_vmain(trans);
+       iwl_pcie_set_pwr(trans, false);
 
        iwl_op_mode_nic_config(trans->op_mode);
 
@@ -435,7 +430,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
 }
 
 static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
-                                  const struct fw_img *fw)
+                                  const struct fw_img *fw, bool run_in_rfkill)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
@@ -454,7 +449,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
        /* If platform's RF_KILL switch is NOT set to KILL */
        hw_rfkill = iwl_is_rfkill_set(trans);
        iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-       if (hw_rfkill)
+       if (hw_rfkill && !run_in_rfkill)
                return -ERFKILL;
 
        iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
@@ -534,12 +529,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 
        iwl_enable_rfkill_int(trans);
 
-       /* wait to make sure we flush pending tasklet*/
-       synchronize_irq(trans_pcie->irq);
-       tasklet_kill(&trans_pcie->irq_tasklet);
-
-       cancel_work_sync(&trans_pcie->rx_replenish);
-
        /* stop and reset the on-board processor */
        iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
@@ -551,46 +540,87 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        clear_bit(STATUS_RFKILL, &trans_pcie->status);
 }
 
-static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
+static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
 {
        /* let the ucode operate on its own */
        iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
                    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 
        iwl_disable_interrupts(trans);
+       iwl_pcie_disable_ict(trans);
+
        iwl_clear_bit(trans, CSR_GP_CNTRL,
                      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       iwl_clear_bit(trans, CSR_GP_CNTRL,
+                     CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+       /*
+        * reset TX queues -- some of their registers reset during S3
+        * so if we don't reset everything here the D3 image would try
+        * to execute some invalid memory upon resume
+        */
+       iwl_trans_pcie_tx_reset(trans);
+
+       iwl_pcie_set_pwr(trans, true);
 }
 
-static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
+                                   enum iwl_d3_status *status)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       int err;
-       bool hw_rfkill;
+       u32 val;
+       int ret;
 
-       trans_pcie->inta_mask = CSR_INI_SET_MASK;
+       iwl_pcie_set_pwr(trans, false);
 
-       if (!trans_pcie->irq_requested) {
-               tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
-                       iwl_pcie_tasklet, (unsigned long)trans);
+       val = iwl_read32(trans, CSR_RESET);
+       if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
+               *status = IWL_D3_STATUS_RESET;
+               return 0;
+       }
 
-               iwl_pcie_alloc_ict(trans);
+       /*
+        * Also enables interrupts - none will happen as the device doesn't
+        * know we're waking it up, only when the opmode actually tells it
+        * after this call.
+        */
+       iwl_pcie_reset_ict(trans);
 
-               err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict,
-                                 IRQF_SHARED, DRV_NAME, trans);
-               if (err) {
-                       IWL_ERR(trans, "Error allocating IRQ %d\n",
-                               trans_pcie->irq);
-                       goto error;
-               }
+       iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-               trans_pcie->irq_requested = true;
+       ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          25000);
+       if (ret) {
+               IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
+               return ret;
        }
 
+       iwl_trans_pcie_tx_reset(trans);
+
+       ret = iwl_pcie_rx_init(trans);
+       if (ret) {
+               IWL_ERR(trans, "Failed to resume the device (RX reset)\n");
+               return ret;
+       }
+
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       *status = IWL_D3_STATUS_ALIVE;
+       return 0;
+}
+
+static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+{
+       bool hw_rfkill;
+       int err;
+
        err = iwl_pcie_prepare_card_hw(trans);
        if (err) {
                IWL_ERR(trans, "Error while preparing HW: %d\n", err);
-               goto err_free_irq;
+               return err;
        }
 
        iwl_pcie_apm_init(trans);
@@ -601,15 +631,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
        hw_rfkill = iwl_is_rfkill_set(trans);
        iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
-       return err;
-
-err_free_irq:
-       trans_pcie->irq_requested = false;
-       free_irq(trans_pcie->irq, trans);
-error:
-       iwl_pcie_free_ict(trans);
-       tasklet_kill(&trans_pcie->irq_tasklet);
-       return err;
+       return 0;
 }
 
 static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
@@ -703,19 +725,21 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
                msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
 
        trans_pcie->command_names = trans_cfg->command_names;
+       trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
 }
 
 void iwl_trans_pcie_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
+       synchronize_irq(trans_pcie->pci_dev->irq);
+       tasklet_kill(&trans_pcie->irq_tasklet);
+
        iwl_pcie_tx_free(trans);
        iwl_pcie_rx_free(trans);
 
-       if (trans_pcie->irq_requested == true) {
-               free_irq(trans_pcie->irq, trans);
-               iwl_pcie_free_ict(trans);
-       }
+       free_irq(trans_pcie->pci_dev->irq, trans);
+       iwl_pcie_free_ict(trans);
 
        pci_disable_msi(trans_pcie->pci_dev);
        iounmap(trans_pcie->hw_base);
@@ -751,13 +775,112 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
        hw_rfkill = iwl_is_rfkill_set(trans);
        iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
-       if (!hw_rfkill)
-               iwl_enable_interrupts(trans);
-
        return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
+static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
+{
+       int ret;
+
+       lockdep_assert_held(&trans->reg_lock);
+
+       /* this bit wakes up the NIC */
+       __iwl_set_bit(trans, CSR_GP_CNTRL,
+                     CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+       /*
+        * These bits say the device is running, and should keep running for
+        * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
+        * but they do not indicate that embedded SRAM is restored yet;
+        * 3945 and 4965 have volatile SRAM, and must save/restore contents
+        * to/from host DRAM when sleeping/waking for power-saving.
+        * Each direction takes approximately 1/4 millisecond; with this
+        * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
+        * series of register accesses are expected (e.g. reading Event Log),
+        * to keep device from sleeping.
+        *
+        * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
+        * SRAM is okay/restored.  We don't check that here because this call
+        * is just for hardware register access; but GP1 MAC_SLEEP check is a
+        * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
+        *
+        * 5000 series and later (including 1000 series) have non-volatile SRAM,
+        * and do not save/restore SRAM when power cycling.
+        */
+       ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+                          (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+                           CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
+       if (unlikely(ret < 0)) {
+               iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
+               if (!silent) {
+                       u32 val = iwl_read32(trans, CSR_GP_CNTRL);
+                       WARN_ONCE(1,
+                                 "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
+                                 val);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
+{
+       lockdep_assert_held(&trans->reg_lock);
+       __iwl_clear_bit(trans, CSR_GP_CNTRL,
+                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+       /*
+        * Above we read the CSR_GP_CNTRL register, which will flush
+        * any previous writes, but we need the write that clears the
+        * MAC_ACCESS_REQ bit to be performed before any other writes
+        * scheduled on different CPUs (after we drop reg_lock).
+        */
+       mmiowb();
+}
+
+static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
+                                  void *buf, int dwords)
+{
+       unsigned long flags;
+       int offs, ret = 0;
+       u32 *vals = buf;
+
+       spin_lock_irqsave(&trans->reg_lock, flags);
+       if (iwl_trans_grab_nic_access(trans, false)) {
+               iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
+               for (offs = 0; offs < dwords; offs++)
+                       vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+               iwl_trans_release_nic_access(trans);
+       } else {
+               ret = -EBUSY;
+       }
+       spin_unlock_irqrestore(&trans->reg_lock, flags);
+       return ret;
+}
+
+static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
+                                   void *buf, int dwords)
+{
+       unsigned long flags;
+       int offs, ret = 0;
+       u32 *vals = buf;
+
+       spin_lock_irqsave(&trans->reg_lock, flags);
+       if (iwl_trans_grab_nic_access(trans, false)) {
+               iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
+               for (offs = 0; offs < dwords; offs++)
+                       iwl_write32(trans, HBUS_TARG_MEM_WDAT,
+                                   vals ? vals[offs] : 0);
+               iwl_trans_release_nic_access(trans);
+       } else {
+               ret = -EBUSY;
+       }
+       spin_unlock_irqrestore(&trans->reg_lock, flags);
+       return ret;
+}
+
 #define IWL_FLUSH_WAIT_MS      2000
 
 static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
@@ -767,6 +890,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
        struct iwl_queue *q;
        int cnt;
        unsigned long now = jiffies;
+       u32 scd_sram_addr;
+       u8 buf[16];
        int ret = 0;
 
        /* waiting for all the tx frames complete might take a while */
@@ -780,11 +905,50 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
                        msleep(1);
 
                if (q->read_ptr != q->write_ptr) {
-                       IWL_ERR(trans, "fail to flush all tx fifo queues\n");
+                       IWL_ERR(trans,
+                               "fail to flush all tx fifo queues Q %d\n", cnt);
                        ret = -ETIMEDOUT;
                        break;
                }
        }
+
+       if (!ret)
+               return 0;
+
+       IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
+               txq->q.read_ptr, txq->q.write_ptr);
+
+       scd_sram_addr = trans_pcie->scd_base_addr +
+                       SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
+       iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+
+       iwl_print_hex_error(trans, buf, sizeof(buf));
+
+       for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++)
+               IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt,
+                       iwl_read_direct32(trans, FH_TX_TRB_REG(cnt)));
+
+       for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
+               u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt));
+               u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
+               bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
+               u32 tbl_dw =
+                       iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr +
+                                            SCD_TRANS_TBL_OFFSET_QUEUE(cnt));
+
+               if (cnt & 0x1)
+                       tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
+               else
+                       tbl_dw = tbl_dw & 0x0000FFFF;
+
+               IWL_ERR(trans,
+                       "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
+                       cnt, active ? "" : "in", fifo, tbl_dw,
+                       iwl_read_prph(trans,
+                                     SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1),
+                       iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
+       }
+
        return ret;
 }
 
@@ -1212,7 +1376,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .start_fw = iwl_trans_pcie_start_fw,
        .stop_device = iwl_trans_pcie_stop_device,
 
-       .wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
+       .d3_suspend = iwl_trans_pcie_d3_suspend,
+       .d3_resume = iwl_trans_pcie_d3_resume,
 
        .send_cmd = iwl_trans_pcie_send_hcmd,
 
@@ -1235,8 +1400,12 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .read32 = iwl_trans_pcie_read32,
        .read_prph = iwl_trans_pcie_read_prph,
        .write_prph = iwl_trans_pcie_write_prph,
+       .read_mem = iwl_trans_pcie_read_mem,
+       .write_mem = iwl_trans_pcie_write_mem,
        .configure = iwl_trans_pcie_configure,
        .set_pmi = iwl_trans_pcie_set_pmi,
+       .grab_nic_access = iwl_trans_pcie_grab_nic_access,
+       .release_nic_access = iwl_trans_pcie_release_nic_access
 };
 
 struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
@@ -1318,7 +1487,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        }
 
        trans->dev = &pdev->dev;
-       trans_pcie->irq = pdev->irq;
        trans_pcie->pci_dev = pdev;
        trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
        trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
@@ -1344,8 +1512,27 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        if (!trans->dev_cmd_pool)
                goto out_pci_disable_msi;
 
+       trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+       tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
+                    iwl_pcie_tasklet, (unsigned long)trans);
+
+       if (iwl_pcie_alloc_ict(trans))
+               goto out_free_cmd_pool;
+
+       err = request_irq(pdev->irq, iwl_pcie_isr_ict,
+                         IRQF_SHARED, DRV_NAME, trans);
+       if (err) {
+               IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
+               goto out_free_ict;
+       }
+
        return trans;
 
+out_free_ict:
+       iwl_pcie_free_ict(trans);
+out_free_cmd_pool:
+       kmem_cache_destroy(trans->dev_cmd_pool);
 out_pci_disable_msi:
        pci_disable_msi(pdev);
 out_pci_release_regions:
index 6c5b867c353ae83cd79404bece14d83989cba6a8..a93f06762b96c83f3a8509419eac12d59efb78d5 100644 (file)
@@ -160,7 +160,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
        IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
                txq->q.read_ptr, txq->q.write_ptr);
 
-       iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+       iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
 
        iwl_print_hex_error(trans, buf, sizeof(buf));
 
@@ -173,9 +173,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
                u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
                bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
                u32 tbl_dw =
-                       iwl_read_targ_mem(trans,
-                                         trans_pcie->scd_base_addr +
-                                         SCD_TRANS_TBL_OFFSET_QUEUE(i));
+                       iwl_trans_read_mem32(trans,
+                                            trans_pcie->scd_base_addr +
+                                            SCD_TRANS_TBL_OFFSET_QUEUE(i));
 
                if (i & 0x1)
                        tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
@@ -237,7 +237,10 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
                break;
        }
 
-       bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+       if (trans_pcie->bc_table_dword)
+               len = DIV_ROUND_UP(len, 4);
+
+       bc_ent = cpu_to_le16(len | (sta_id << 12));
 
        scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
 
@@ -306,6 +309,9 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
                                return;
                        }
 
+                       IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id,
+                                    txq->q.write_ptr);
+
                        iwl_write_direct32(trans, HBUS_TARG_WRPTR,
                                     txq->q.write_ptr | (txq_id << 8));
 
@@ -612,7 +618,7 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
        if (txq->q.n_bd) {
                dma_free_coherent(dev, sizeof(struct iwl_tfd) *
                                  txq->q.n_bd, txq->tfds, txq->q.dma_addr);
-               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+               txq->q.dma_addr = 0;
        }
 
        kfree(txq->entries);
@@ -638,9 +644,11 @@ static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
 void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 a;
+       int nq = trans->cfg->base_params->num_of_queues;
        int chan;
        u32 reg_val;
+       int clear_dwords = (SCD_TRANS_TBL_OFFSET_QUEUE(nq) -
+                               SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(u32);
 
        /* make sure all queue are not stopped/used */
        memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
@@ -652,20 +660,10 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
        WARN_ON(scd_base_addr != 0 &&
                scd_base_addr != trans_pcie->scd_base_addr);
 
-       a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
-       /* reset conext data memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-       /* reset tx status memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-       for (; a < trans_pcie->scd_base_addr +
-              SCD_TRANS_TBL_OFFSET_QUEUE(
-                               trans->cfg->base_params->num_of_queues);
-              a += 4)
-               iwl_write_targ_mem(trans, a, 0);
+       /* reset context data, TX status and translation data */
+       iwl_trans_write_mem(trans, trans_pcie->scd_base_addr +
+                                  SCD_CONTEXT_MEM_LOWER_BOUND,
+                           NULL, clear_dwords);
 
        iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
                       trans_pcie->scd_bc_tbls.dma >> 10);
@@ -697,6 +695,29 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
                            APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 }
 
+void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int txq_id;
+
+       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+            txq_id++) {
+               struct iwl_txq *txq = &trans_pcie->txq[txq_id];
+
+               iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
+                                  txq->q.dma_addr >> 8);
+               iwl_pcie_txq_unmap(trans, txq_id);
+               txq->q.read_ptr = 0;
+               txq->q.write_ptr = 0;
+       }
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
+                          trans_pcie->kw.dma >> 4);
+
+       iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr);
+}
+
 /*
  * iwl_pcie_tx_stop - Stop all Tx DMA channels
  */
@@ -1002,14 +1023,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
        tbl_dw_addr = trans_pcie->scd_base_addr +
                        SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
 
-       tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
+       tbl_dw = iwl_trans_read_mem32(trans, tbl_dw_addr);
 
        if (txq_id & 0x1)
                tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
        else
                tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
 
-       iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
+       iwl_trans_write_mem32(trans, tbl_dw_addr, tbl_dw);
 
        return 0;
 }
@@ -1068,9 +1089,9 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
        iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
 
        /* Set up Tx window size and frame limit for this queue */
-       iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+       iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
                        SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
-       iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+       iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
                        SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
                        ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
                                SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
@@ -1101,8 +1122,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
 
        iwl_pcie_txq_set_inactive(trans, txq_id);
 
-       _iwl_write_targ_mem_dwords(trans, stts_addr,
-                                  zero_val, ARRAY_SIZE(zero_val));
+       iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+                           ARRAY_SIZE(zero_val));
 
        iwl_pcie_txq_unmap(trans, txq_id);
 
@@ -1642,10 +1663,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
        tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
 
-       IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
-                    le16_to_cpu(dev_cmd->hdr.sequence));
-       IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-
        /* Set up entry for this TFD in Tx byte-count array */
        iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
 
index ec6d5d6b452e7aebf8b8d782460e7b0263c121a0..230f8ebbe28921f6786e250b4f88cb421c013385 100644 (file)
@@ -2132,6 +2132,21 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
        lbs_deb_leave(LBS_DEB_CFG80211);
 }
 
+static void lbs_reg_notifier(struct wiphy *wiphy,
+                            struct regulatory_request *request)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+                       "callback for domain %c%c\n", request->alpha2[0],
+                       request->alpha2[1]);
+
+       memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+       if (lbs_iface_active(priv))
+               lbs_set_11d_domain_info(priv);
+
+       lbs_deb_leave(LBS_DEB_CFG80211);
+}
 
 /*
  * This function get's called after lbs_setup_firmware() determined the
@@ -2184,24 +2199,6 @@ int lbs_cfg_register(struct lbs_private *priv)
        return ret;
 }
 
-int lbs_reg_notifier(struct wiphy *wiphy,
-               struct regulatory_request *request)
-{
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       int ret = 0;
-
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
-                       "callback for domain %c%c\n", request->alpha2[0],
-                       request->alpha2[1]);
-
-       memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
-       if (lbs_iface_active(priv))
-               ret = lbs_set_11d_domain_info(priv);
-
-       lbs_deb_leave(LBS_DEB_CFG80211);
-       return ret;
-}
-
 void lbs_scan_deinit(struct lbs_private *priv)
 {
        lbs_deb_enter(LBS_DEB_CFG80211);
index 558168ce634d519d67201d92c1992163550f4b4b..10995f59fe34a1796db45e914196fc7a03248c07 100644 (file)
@@ -10,9 +10,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
 int lbs_cfg_register(struct lbs_private *priv);
 void lbs_cfg_free(struct lbs_private *priv);
 
-int lbs_reg_notifier(struct wiphy *wiphy,
-               struct regulatory_request *request);
-
 void lbs_send_disconnect_notification(struct lbs_private *priv);
 void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
 
index ff9085502beacba1f66990b93e225fea6d3d2fa0..b73e497fe77049b59d13f9c822492c2dceb2aba1 100644 (file)
@@ -48,6 +48,10 @@ static int channels = 1;
 module_param(channels, int, 0444);
 MODULE_PARM_DESC(channels, "Number of concurrent channels");
 
+static bool paged_rx = false;
+module_param(paged_rx, bool, 0644);
+MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones");
+
 /**
  * enum hwsim_regtest - the type of regulatory tests we offer
  *
@@ -333,11 +337,11 @@ struct mac80211_hwsim_data {
        int scan_chan_idx;
 
        struct ieee80211_channel *channel;
-       unsigned long beacon_int; /* in jiffies unit */
+       u64 beacon_int  /* beacon interval in us */;
        unsigned int rx_filter;
        bool started, idle, scanning;
        struct mutex mutex;
-       struct timer_list beacon_timer;
+       struct tasklet_hrtimer beacon_timer;
        enum ps_mode {
                PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
        } ps;
@@ -357,7 +361,10 @@ struct mac80211_hwsim_data {
        int power_level;
 
        /* difference between this hw's clock and the real clock, in usecs */
-       u64 tsf_offset;
+       s64 tsf_offset;
+       s64 bcn_delta;
+       /* absolute beacon transmission time. Used to cover up "tx" delay. */
+       u64 abs_bcn_ts;
 };
 
 
@@ -405,15 +412,19 @@ static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
        return NETDEV_TX_OK;
 }
 
+static inline u64 mac80211_hwsim_get_tsf_raw(void)
+{
+       return ktime_to_us(ktime_get_real());
+}
+
 static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data)
 {
-       struct timeval tv = ktime_to_timeval(ktime_get_real());
-       u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
+       u64 now = mac80211_hwsim_get_tsf_raw();
        return cpu_to_le64(now + data->tsf_offset);
 }
 
 static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
-               struct ieee80211_vif *vif)
+                                 struct ieee80211_vif *vif)
 {
        struct mac80211_hwsim_data *data = hw->priv;
        return le64_to_cpu(__mac80211_hwsim_get_tsf(data));
@@ -423,9 +434,13 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
                struct ieee80211_vif *vif, u64 tsf)
 {
        struct mac80211_hwsim_data *data = hw->priv;
-       struct timeval tv = ktime_to_timeval(ktime_get_real());
-       u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
-       data->tsf_offset = tsf - now;
+       u64 now = mac80211_hwsim_get_tsf(hw, vif);
+       u32 bcn_int = data->beacon_int;
+       s64 delta = tsf - now;
+
+       data->tsf_offset += delta;
+       /* adjust after beaconing with new timestamp at old TBTT */
+       data->bcn_delta = do_div(delta, bcn_int);
 }
 
 static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
@@ -696,7 +711,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_rx_status rx_status;
-       struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
+       u64 now;
 
        memset(&rx_status, 0, sizeof(rx_status));
        rx_status.flag |= RX_FLAG_MACTIME_START;
@@ -722,11 +737,23 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
        secpath_reset(skb);
        nf_reset(skb);
 
+       /*
+        * Get absolute mactime here so all HWs RX at the "same time", and
+        * absolute TX time for beacon mactime so the timestamp matches.
+        * Giving beacons a different mactime than non-beacons looks messy, but
+        * it helps the Toffset be exact and a ~10us mactime discrepancy
+        * probably doesn't really matter.
+        */
+       if (ieee80211_is_beacon(hdr->frame_control) ||
+           ieee80211_is_probe_resp(hdr->frame_control))
+               now = data->abs_bcn_ts;
+       else
+               now = mac80211_hwsim_get_tsf_raw();
+
        /* Copy skb to all enabled radios that are on the current frequency */
        spin_lock(&hwsim_radio_lock);
        list_for_each_entry(data2, &hwsim_radios, list) {
                struct sk_buff *nskb;
-               struct ieee80211_mgmt *mgmt;
                struct tx_iter_data tx_iter_data = {
                        .receive = false,
                        .channel = chan,
@@ -755,24 +782,30 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
                 * reserve some space for our vendor and the normal
                 * radiotap header, since we're copying anyway
                 */
-               nskb = skb_copy_expand(skb, 64, 0, GFP_ATOMIC);
-               if (nskb == NULL)
-                       continue;
+               if (skb->len < PAGE_SIZE && paged_rx) {
+                       struct page *page = alloc_page(GFP_ATOMIC);
+
+                       if (!page)
+                               continue;
+
+                       nskb = dev_alloc_skb(128);
+                       if (!nskb) {
+                               __free_page(page);
+                               continue;
+                       }
+
+                       memcpy(page_address(page), skb->data, skb->len);
+                       skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len);
+               } else {
+                       nskb = skb_copy(skb, GFP_ATOMIC);
+                       if (!nskb)
+                               continue;
+               }
 
                if (mac80211_hwsim_addr_match(data2, hdr->addr1))
                        ack = true;
 
-               /* set bcn timestamp relative to receiver mactime */
-               rx_status.mactime =
-                               le64_to_cpu(__mac80211_hwsim_get_tsf(data2));
-               mgmt = (struct ieee80211_mgmt *) nskb->data;
-               if (ieee80211_is_beacon(mgmt->frame_control) ||
-                   ieee80211_is_probe_resp(mgmt->frame_control))
-                       mgmt->u.beacon.timestamp = cpu_to_le64(
-                               rx_status.mactime +
-                               (data->tsf_offset - data2->tsf_offset) +
-                               24 * 8 * 10 / txrate->bitrate);
-
+               rx_status.mactime = now + data2->tsf_offset;
 #if 0
                /*
                 * Don't enable this code by default as the OUI 00:00:00
@@ -896,7 +929,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
 {
        struct mac80211_hwsim_data *data = hw->priv;
        data->started = false;
-       del_timer(&data->beacon_timer);
+       tasklet_hrtimer_cancel(&data->beacon_timer);
        wiphy_debug(hw->wiphy, "%s\n", __func__);
 }
 
@@ -962,7 +995,11 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
 static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
                                     struct ieee80211_vif *vif)
 {
-       struct ieee80211_hw *hw = arg;
+       struct mac80211_hwsim_data *data = arg;
+       struct ieee80211_hw *hw = data->hw;
+       struct ieee80211_tx_info *info;
+       struct ieee80211_rate *txrate;
+       struct ieee80211_mgmt *mgmt;
        struct sk_buff *skb;
 
        hwsim_check_magic(vif);
@@ -975,26 +1012,48 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
        skb = ieee80211_beacon_get(hw, vif);
        if (skb == NULL)
                return;
+       info = IEEE80211_SKB_CB(skb);
+       txrate = ieee80211_get_tx_rate(hw, info);
+
+       mgmt = (struct ieee80211_mgmt *) skb->data;
+       /* fake header transmission time */
+       data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw();
+       mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
+                                              data->tsf_offset +
+                                              24 * 8 * 10 / txrate->bitrate);
 
        mac80211_hwsim_tx_frame(hw, skb,
                                rcu_dereference(vif->chanctx_conf)->def.chan);
 }
 
-
-static void mac80211_hwsim_beacon(unsigned long arg)
+static enum hrtimer_restart
+mac80211_hwsim_beacon(struct hrtimer *timer)
 {
-       struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
-       struct mac80211_hwsim_data *data = hw->priv;
+       struct mac80211_hwsim_data *data =
+               container_of(timer, struct mac80211_hwsim_data,
+                            beacon_timer.timer);
+       struct ieee80211_hw *hw = data->hw;
+       u64 bcn_int = data->beacon_int;
+       ktime_t next_bcn;
 
        if (!data->started)
-               return;
+               goto out;
 
        ieee80211_iterate_active_interfaces_atomic(
                hw, IEEE80211_IFACE_ITER_NORMAL,
-               mac80211_hwsim_beacon_tx, hw);
+               mac80211_hwsim_beacon_tx, data);
+
+       /* beacon at new TBTT + beacon interval */
+       if (data->bcn_delta) {
+               bcn_int -= data->bcn_delta;
+               data->bcn_delta = 0;
+       }
 
-       data->beacon_timer.expires = jiffies + data->beacon_int;
-       add_timer(&data->beacon_timer);
+       next_bcn = ktime_add(hrtimer_get_expires(timer),
+                            ns_to_ktime(bcn_int * 1000));
+       tasklet_hrtimer_start(&data->beacon_timer, next_bcn, HRTIMER_MODE_ABS);
+out:
+       return HRTIMER_NORESTART;
 }
 
 static const char *hwsim_chantypes[] = {
@@ -1032,9 +1091,16 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 
        data->power_level = conf->power_level;
        if (!data->started || !data->beacon_int)
-               del_timer(&data->beacon_timer);
-       else
-               mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
+               tasklet_hrtimer_cancel(&data->beacon_timer);
+       else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
+               u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
+               u32 bcn_int = data->beacon_int;
+               u64 until_tbtt = bcn_int - do_div(tsf, bcn_int);
+
+               tasklet_hrtimer_start(&data->beacon_timer,
+                                     ns_to_ktime(until_tbtt * 1000),
+                                     HRTIMER_MODE_REL);
+       }
 
        return 0;
 }
@@ -1084,12 +1150,26 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_BEACON_INT) {
                wiphy_debug(hw->wiphy, "  BCNINT: %d\n", info->beacon_int);
-               data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000;
-               if (WARN_ON(!data->beacon_int))
-                       data->beacon_int = 1;
-               if (data->started)
-                       mod_timer(&data->beacon_timer,
-                                 jiffies + data->beacon_int);
+               data->beacon_int = info->beacon_int * 1024;
+       }
+
+       if (changed & BSS_CHANGED_BEACON_ENABLED) {
+               wiphy_debug(hw->wiphy, "  BCN EN: %d\n", info->enable_beacon);
+               if (data->started &&
+                   !hrtimer_is_queued(&data->beacon_timer.timer) &&
+                   info->enable_beacon) {
+                       u64 tsf, until_tbtt;
+                       u32 bcn_int;
+                       if (WARN_ON(!data->beacon_int))
+                               data->beacon_int = 1000 * 1024;
+                       tsf = mac80211_hwsim_get_tsf(hw, vif);
+                       bcn_int = data->beacon_int;
+                       until_tbtt = bcn_int - do_div(tsf, bcn_int);
+                       tasklet_hrtimer_start(&data->beacon_timer,
+                                             ns_to_ktime(until_tbtt * 1000),
+                                             HRTIMER_MODE_REL);
+               } else if (!info->enable_beacon)
+                       tasklet_hrtimer_cancel(&data->beacon_timer);
        }
 
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@@ -1292,7 +1372,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
        case IEEE80211_AMPDU_TX_START:
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -2370,8 +2452,9 @@ static int __init init_mac80211_hwsim(void)
                                                        data->debugfs, data,
                                                        &hwsim_fops_group);
 
-               setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
-                           (unsigned long) hw);
+               tasklet_hrtimer_init(&data->beacon_timer,
+                                    mac80211_hwsim_beacon,
+                                    CLOCK_REALTIME, HRTIMER_MODE_ABS);
 
                list_add_tail(&data->list, &hwsim_radios);
        }
index 245a371f1a43a4746bda49912a4a2d656d5cf75e..9cd6216c61e6d802e140090b598f9f09e9d894c6 100644 (file)
@@ -53,7 +53,9 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
               sizeof(sband->ht_cap.mcs));
 
        if (priv->bss_mode == NL80211_IFTYPE_STATION ||
-           sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+           (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
+            (priv->adapter->sec_chan_offset !=
+                                       IEEE80211_HT_PARAM_CHA_SEC_NONE)))
                /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
                SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
 
index 68d52cfc1ebd250a55a43c8b641344d7d6999461..af8fe6352eed143baca5fbeb5fee807c2964dc99 100644 (file)
@@ -278,14 +278,16 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
                break;
        case -1:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
                        __func__, ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
                return 0;
        case -EINPROGRESS:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
index cdb11b3964e27dd68de20ac68ab8442772a070a1..ab92e799cf75fa4bb09b97b9e6642c07c733b911 100644 (file)
@@ -519,8 +519,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
  *      - Set by user
  *      - Set bt Country IE
  */
-static int mwifiex_reg_notifier(struct wiphy *wiphy,
-                               struct regulatory_request *request)
+static void mwifiex_reg_notifier(struct wiphy *wiphy,
+                                struct regulatory_request *request)
 {
        struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
 
@@ -540,8 +540,6 @@ static int mwifiex_reg_notifier(struct wiphy *wiphy,
                break;
        }
        mwifiex_send_domain_info_cmd_fw(wiphy);
-
-       return 0;
 }
 
 /*
@@ -1327,6 +1325,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
        }
 
        mwifiex_set_ht_params(priv, bss_cfg, params);
+       mwifiex_set_wmm_params(priv, bss_cfg, params);
 
        if (params->inactivity_timeout > 0) {
                /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
@@ -2104,7 +2103,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
        dev->ieee80211_ptr = priv->wdev;
        dev->ieee80211_ptr->iftype = priv->bss_mode;
        memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
-       memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
        SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
 
        dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
@@ -2248,6 +2246,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
+                       WIPHY_FLAG_AP_UAPSD |
                        WIPHY_FLAG_CUSTOM_REGULATORY |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
index e9357d87d3279f7ba1d19c8246347f44ca46a269..e8a569aaa2e8ca24298e8e1e25161bd5a9379943 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/wait.h>
 #include <linux/timer.h>
 #include <linux/ieee80211.h>
+#include <net/mac80211.h>
 
 
 #define MWIFIEX_MAX_BSS_NUM         (3)
@@ -58,6 +59,8 @@
 #define MWIFIEX_RTS_MAX_VALUE              (2347)
 #define MWIFIEX_FRAG_MIN_VALUE             (256)
 #define MWIFIEX_FRAG_MAX_VALUE             (2346)
+#define MWIFIEX_WMM_VERSION                0x01
+#define MWIFIEX_WMM_SUBTYPE                0x01
 
 #define MWIFIEX_RETRY_LIMIT                14
 #define MWIFIEX_SDIO_BLOCK_SIZE            256
@@ -126,4 +129,19 @@ enum mwifiex_wmm_ac_e {
        WMM_AC_VI,
        WMM_AC_VO
 } __packed;
+
+struct ieee_types_wmm_ac_parameters {
+       u8 aci_aifsn_bitmap;
+       u8 ecw_bitmap;
+       __le16 tx_op_limit;
+} __packed;
+
+struct mwifiex_types_wmm_info {
+       u8 oui[4];
+       u8 subtype;
+       u8 version;
+       u8 qos_info;
+       u8 reserved;
+       struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
+} __packed;
 #endif /* !_MWIFIEX_DECL_H_ */
index 4dc8e2e9a889c06b3e8d41b352bc45c8e20efc88..ebe2f6a7984ce927ab75c689c52d50ba7842bf22 100644 (file)
@@ -330,6 +330,9 @@ enum P2P_MODES {
 #define HOST_SLEEP_CFG_GPIO_DEF                0xff
 #define HOST_SLEEP_CFG_GAP_DEF         0
 
+#define MWIFIEX_TIMEOUT_FOR_AP_RESP            0xfffc
+#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT       2
+
 #define CMD_F_HOSTCMD           (1 << 0)
 #define CMD_F_CANCELED          (1 << 1)
 
@@ -1131,12 +1134,6 @@ struct ieee_types_vendor_header {
        u8 version;
 } __packed;
 
-struct ieee_types_wmm_ac_parameters {
-       u8 aci_aifsn_bitmap;
-       u8 ecw_bitmap;
-       __le16 tx_op_limit;
-} __packed;
-
 struct ieee_types_wmm_parameter {
        /*
         * WMM Parameter IE - Vendor Specific Header:
@@ -1186,6 +1183,11 @@ struct mwifiex_ie_types_htcap {
        struct ieee80211_ht_cap ht_cap;
 } __packed;
 
+struct mwifiex_ie_types_wmmcap {
+       struct mwifiex_ie_types_header header;
+       struct mwifiex_types_wmm_info wmm_info;
+} __packed;
+
 struct mwifiex_ie_types_htinfo {
        struct mwifiex_ie_types_header header;
        struct ieee80211_ht_operation ht_oper;
index 39f03ce5a5b1cf50bfde4ec291438bc828a2dc22..e00b8060aff7512228ef4de873a70f41a3e8219a 100644 (file)
@@ -591,6 +591,12 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
                                return -1;
                }
        }
+
+       if (adapter->if_ops.init_fw_port) {
+               if (adapter->if_ops.init_fw_port(adapter))
+                       return -1;
+       }
+
        for (i = 0; i < adapter->priv_num; i++) {
                if (adapter->priv[i]) {
                        ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
index 4e31c6013ebe5d73db79e427ee3296c5daa940c5..6095b3e53f4e6c5509240aafa29623d20c5b0e58 100644 (file)
@@ -20,7 +20,6 @@
 #ifndef _MWIFIEX_IOCTL_H_
 #define _MWIFIEX_IOCTL_H_
 
-#include <net/mac80211.h>
 #include <net/lib80211.h>
 
 enum {
@@ -107,6 +106,8 @@ struct mwifiex_uap_bss_param {
        u8 rates[MWIFIEX_SUPPORTED_RATES];
        u32 sta_ao_timer;
        u32 ps_sta_ao_timer;
+       u8 qos_info;
+       struct mwifiex_types_wmm_info wmm_info;
 };
 
 enum {
index 88664ae667ba65ea18e9c27410f26095e1931309..893d809ba83c555f25062bf9b5953814021f1aa9 100644 (file)
@@ -615,23 +615,33 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
        struct ieee_types_assoc_rsp *assoc_rsp;
        struct mwifiex_bssdescriptor *bss_desc;
        u8 enable_data = true;
+       u16 cap_info, status_code;
 
        assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
 
+       cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
+       status_code = le16_to_cpu(assoc_rsp->status_code);
+
        priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
                                   sizeof(priv->assoc_rsp_buf));
 
        memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
 
-       if (le16_to_cpu(assoc_rsp->status_code)) {
+       if (status_code) {
                priv->adapter->dbg.num_cmd_assoc_failure++;
                dev_err(priv->adapter->dev,
                        "ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n",
-                       le16_to_cpu(assoc_rsp->status_code),
-                       le16_to_cpu(assoc_rsp->cap_info_bitmap),
-                       le16_to_cpu(assoc_rsp->a_id));
+                       status_code, cap_info, le16_to_cpu(assoc_rsp->a_id));
+
+               if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) {
+                       if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT)
+                               ret = WLAN_STATUS_AUTH_TIMEOUT;
+                       else
+                               ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               } else {
+                       ret = status_code;
+               }
 
-               ret = le16_to_cpu(assoc_rsp->status_code);
                goto done;
        }
 
@@ -969,6 +979,16 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                                        priv->adapter->config_bands);
                mwifiex_fill_cap_info(priv, radio_type, ht_cap);
 
+               if (adapter->sec_chan_offset ==
+                                       IEEE80211_HT_PARAM_CHA_SEC_NONE) {
+                       u16 tmp_ht_cap;
+
+                       tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info);
+                       tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40;
+                       ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap);
+               }
+
                pos += sizeof(struct mwifiex_ie_types_htcap);
                cmd_append_size += sizeof(struct mwifiex_ie_types_htcap);
 
index 1b3cfc82194081606e21988f7dbc03a53c854df7..51044e3ea89b88aaffb301918ab47bfc82b00937 100644 (file)
@@ -599,8 +599,10 @@ struct mwifiex_if_ops {
        int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *);
        int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
        int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *);
+       int (*init_fw_port) (struct mwifiex_adapter *);
        int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
        void (*card_reset) (struct mwifiex_adapter *);
+       int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
 };
 
 struct mwifiex_adapter {
@@ -890,6 +892,10 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv,
                           struct cfg80211_ap_settings *params);
 void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
                           struct cfg80211_ap_settings *params);
+void
+mwifiex_set_wmm_params(struct mwifiex_private *priv,
+                      struct mwifiex_uap_bss_param *bss_cfg,
+                      struct cfg80211_ap_settings *params);
 
 /*
  * This function checks if the queuing is RA based or not.
index b879e1338a54f5347a7a5f0b955b98a3f3566b66..237949c070ccb43478dddee1cead95ca02a908cc 100644 (file)
@@ -39,17 +39,20 @@ static struct semaphore add_remove_card_sem;
 static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
 static int mwifiex_pcie_resume(struct pci_dev *pdev);
 
-/*
- * This function is called after skb allocation to update
- * "skb->cb" with physical address of data pointer.
- */
-static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb)
+static int
+mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+                      int size, int flags)
 {
-       phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
-
-       *buf_pa = (phys_addr_t)virt_to_phys(skb->data);
+       struct pcie_service_card *card = adapter->card;
+       dma_addr_t buf_pa;
 
-       return buf_pa;
+       buf_pa = pci_map_single(card->dev, skb->data, size, flags);
+       if (pci_dma_mapping_error(card->dev, buf_pa)) {
+               dev_err(adapter->dev, "failed to map pci memory!\n");
+               return -1;
+       }
+       memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t));
+       return 0;
 }
 
 /*
@@ -60,8 +63,8 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
        u32 *cookie_addr;
        struct pcie_service_card *card = adapter->card;
 
-       if (card->sleep_cookie) {
-               cookie_addr = (u32 *)card->sleep_cookie->data;
+       if (card->sleep_cookie_vbase) {
+               cookie_addr = (u32 *)card->sleep_cookie_vbase;
                dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
                        *cookie_addr);
                if (*cookie_addr == FW_AWAKE_COOKIE)
@@ -366,9 +369,7 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
-       struct sk_buff *skb;
        int i;
-       phys_addr_t *buf_pa;
 
        /*
         * driver maintaines the write pointer and firmware maintaines the read
@@ -384,16 +385,18 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
                                                        MWIFIEX_MAX_TXRX_BD;
        dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
                card->txbd_ring_size);
-       card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
+       card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
+                                                    card->txbd_ring_size,
+                                                    &card->txbd_ring_pbase);
        if (!card->txbd_ring_vbase) {
-               dev_err(adapter->dev, "Unable to alloc buffer for txbd ring\n");
+               dev_err(adapter->dev,
+                       "allocate consistent memory (%d bytes) failed!\n",
+                       card->txbd_ring_size);
                return -ENOMEM;
        }
-       card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
-
        dev_dbg(adapter->dev,
                "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
-               card->txbd_ring_vbase, (u32)card->txbd_ring_pbase,
+               card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
                (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
 
        for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
@@ -402,24 +405,9 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
                                      (sizeof(struct mwifiex_pcie_buf_desc)
                                       * i));
 
-               /* Allocate buffer here so that firmware can DMA data from it */
-               skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
-               if (!skb) {
-                       dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n");
-                       kfree(card->txbd_ring_vbase);
-                       return -ENOMEM;
-               }
-               buf_pa = mwifiex_update_sk_buff_pa(skb);
-
-               skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
-               dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, "
-                       "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-                       skb, skb->data, (u32)*buf_pa,
-                       (u32)(((u64)*buf_pa >> 32)), skb->len);
-
-               card->tx_buf_list[i] = skb;
-               card->txbd_ring[i]->paddr = *buf_pa;
-               card->txbd_ring[i]->len = (u16)skb->len;
+               card->tx_buf_list[i] = NULL;
+               card->txbd_ring[i]->paddr = 0;
+               card->txbd_ring[i]->len = 0;
                card->txbd_ring[i]->flags = 0;
        }
 
@@ -429,11 +417,16 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
+       struct sk_buff *skb;
        int i;
 
        for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-               if (card->tx_buf_list[i])
-                       dev_kfree_skb_any(card->tx_buf_list[i]);
+               if (card->tx_buf_list[i]) {
+                       skb = card->tx_buf_list[i];
+                       pci_unmap_single(card->dev, card->txbd_ring[i]->paddr,
+                                        skb->len, PCI_DMA_TODEVICE);
+                       dev_kfree_skb_any(skb);
+               }
                card->tx_buf_list[i] = NULL;
                card->txbd_ring[i]->paddr = 0;
                card->txbd_ring[i]->len = 0;
@@ -441,11 +434,15 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
                card->txbd_ring[i] = NULL;
        }
 
-       kfree(card->txbd_ring_vbase);
+       if (card->txbd_ring_vbase)
+               pci_free_consistent(card->dev, card->txbd_ring_size,
+                                   card->txbd_ring_vbase,
+                                   card->txbd_ring_pbase);
        card->txbd_ring_size = 0;
        card->txbd_wrptr = 0;
        card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
        card->txbd_ring_vbase = NULL;
+       card->txbd_ring_pbase = 0;
 
        return 0;
 }
@@ -458,7 +455,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        struct sk_buff *skb;
        int i;
-       phys_addr_t *buf_pa;
+       dma_addr_t buf_pa;
 
        /*
         * driver maintaines the read pointer and firmware maintaines the write
@@ -472,13 +469,15 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
                                                        MWIFIEX_MAX_TXRX_BD;
        dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
                card->rxbd_ring_size);
-       card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL);
+       card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
+                                                    card->rxbd_ring_size,
+                                                    &card->rxbd_ring_pbase);
        if (!card->rxbd_ring_vbase) {
-               dev_err(adapter->dev, "Unable to allocate buffer for "
-                               "rxbd_ring.\n");
+               dev_err(adapter->dev,
+                       "allocate consistent memory (%d bytes) failed!\n",
+                       card->rxbd_ring_size);
                return -ENOMEM;
        }
-       card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase);
 
        dev_dbg(adapter->dev,
                "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
@@ -500,16 +499,20 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
                        kfree(card->rxbd_ring_vbase);
                        return -ENOMEM;
                }
-               buf_pa = mwifiex_update_sk_buff_pa(skb);
-               skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
+               if (mwifiex_map_pci_memory(adapter, skb,
+                                          MWIFIEX_RX_DATA_BUF_SIZE,
+                                          PCI_DMA_FROMDEVICE))
+                       return -1;
+
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
 
                dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
                        "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-                       skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+                       skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32),
                        skb->len);
 
                card->rx_buf_list[i] = skb;
-               card->rxbd_ring[i]->paddr = *buf_pa;
+               card->rxbd_ring[i]->paddr = buf_pa;
                card->rxbd_ring[i]->len = (u16)skb->len;
                card->rxbd_ring[i]->flags = 0;
        }
@@ -523,11 +526,17 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
+       struct sk_buff *skb;
        int i;
 
        for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-               if (card->rx_buf_list[i])
-                       dev_kfree_skb_any(card->rx_buf_list[i]);
+               if (card->rx_buf_list[i]) {
+                       skb = card->rx_buf_list[i];
+                       pci_unmap_single(card->dev, card->rxbd_ring[i]->paddr ,
+                                        MWIFIEX_RX_DATA_BUF_SIZE,
+                                        PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb_any(skb);
+               }
                card->rx_buf_list[i] = NULL;
                card->rxbd_ring[i]->paddr = 0;
                card->rxbd_ring[i]->len = 0;
@@ -535,11 +544,15 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
                card->rxbd_ring[i] = NULL;
        }
 
-       kfree(card->rxbd_ring_vbase);
+       if (card->rxbd_ring_vbase)
+               pci_free_consistent(card->dev, card->rxbd_ring_size,
+                                   card->rxbd_ring_vbase,
+                                   card->rxbd_ring_pbase);
        card->rxbd_ring_size = 0;
        card->rxbd_wrptr = 0;
        card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
        card->rxbd_ring_vbase = NULL;
+       card->rxbd_ring_pbase = 0;
 
        return 0;
 }
@@ -552,7 +565,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        struct sk_buff *skb;
        int i;
-       phys_addr_t *buf_pa;
+       dma_addr_t buf_pa;
 
        /*
         * driver maintaines the read pointer and firmware maintaines the write
@@ -566,13 +579,15 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
                                                        MWIFIEX_MAX_EVT_BD;
        dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
                card->evtbd_ring_size);
-       card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL);
+       card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
+                                                     card->evtbd_ring_size,
+                                                     &card->evtbd_ring_pbase);
        if (!card->evtbd_ring_vbase) {
                dev_err(adapter->dev,
-                       "Unable to allocate buffer. Terminating download\n");
+                       "allocate consistent memory (%d bytes) failed!\n",
+                       card->evtbd_ring_size);
                return -ENOMEM;
        }
-       card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase);
 
        dev_dbg(adapter->dev,
                "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
@@ -594,16 +609,20 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
                        kfree(card->evtbd_ring_vbase);
                        return -ENOMEM;
                }
-               buf_pa = mwifiex_update_sk_buff_pa(skb);
                skb_put(skb, MAX_EVENT_SIZE);
 
+               if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
+                                          PCI_DMA_FROMDEVICE))
+                       return -1;
+
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
                dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
                        "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-                       skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+                       skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32),
                        skb->len);
 
                card->evt_buf_list[i] = skb;
-               card->evtbd_ring[i]->paddr = *buf_pa;
+               card->evtbd_ring[i]->paddr = buf_pa;
                card->evtbd_ring[i]->len = (u16)skb->len;
                card->evtbd_ring[i]->flags = 0;
        }
@@ -617,11 +636,16 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
+       struct sk_buff *skb;
        int i;
 
        for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
-               if (card->evt_buf_list[i])
-                       dev_kfree_skb_any(card->evt_buf_list[i]);
+               if (card->evt_buf_list[i]) {
+                       skb = card->evt_buf_list[i];
+                       pci_unmap_single(card->dev, card->evtbd_ring[i]->paddr,
+                                        MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb_any(skb);
+               }
                card->evt_buf_list[i] = NULL;
                card->evtbd_ring[i]->paddr = 0;
                card->evtbd_ring[i]->len = 0;
@@ -629,11 +653,15 @@ static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
                card->evtbd_ring[i] = NULL;
        }
 
-       kfree(card->evtbd_ring_vbase);
+       if (card->evtbd_ring_vbase)
+               pci_free_consistent(card->dev, card->evtbd_ring_size,
+                                   card->evtbd_ring_vbase,
+                                   card->evtbd_ring_pbase);
        card->evtbd_wrptr = 0;
        card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
        card->evtbd_ring_size = 0;
        card->evtbd_ring_vbase = NULL;
+       card->evtbd_ring_pbase = 0;
 
        return 0;
 }
@@ -653,21 +681,12 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
                        "Unable to allocate skb for command response data.\n");
                return -ENOMEM;
        }
-       mwifiex_update_sk_buff_pa(skb);
        skb_put(skb, MWIFIEX_UPLD_SIZE);
-       card->cmdrsp_buf = skb;
+       if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+                                  PCI_DMA_FROMDEVICE))
+               return -1;
 
-       skb = NULL;
-       /* Allocate memory for sending command to firmware */
-       skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
-       if (!skb) {
-               dev_err(adapter->dev,
-                       "Unable to allocate skb for command data.\n");
-               return -ENOMEM;
-       }
-       mwifiex_update_sk_buff_pa(skb);
-       skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER);
-       card->cmd_buf = skb;
+       card->cmdrsp_buf = skb;
 
        return 0;
 }
@@ -678,18 +697,26 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card;
+       dma_addr_t buf_pa;
 
        if (!adapter)
                return 0;
 
        card = adapter->card;
 
-       if (card && card->cmdrsp_buf)
+       if (card && card->cmdrsp_buf) {
+               MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+                                PCI_DMA_FROMDEVICE);
                dev_kfree_skb_any(card->cmdrsp_buf);
+       }
 
-       if (card && card->cmd_buf)
+       if (card && card->cmd_buf) {
+               MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER,
+                                PCI_DMA_TODEVICE);
                dev_kfree_skb_any(card->cmd_buf);
-
+       }
        return 0;
 }
 
@@ -698,27 +725,19 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
  */
 static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
 {
-       struct sk_buff *skb;
        struct pcie_service_card *card = adapter->card;
 
-       /* Allocate memory for sleep cookie */
-       skb = dev_alloc_skb(sizeof(u32));
-       if (!skb) {
-               dev_err(adapter->dev,
-                       "Unable to allocate skb for sleep cookie!\n");
+       card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32),
+                                                    &card->sleep_cookie_pbase);
+       if (!card->sleep_cookie_vbase) {
+               dev_err(adapter->dev, "pci_alloc_consistent failed!\n");
                return -ENOMEM;
        }
-       mwifiex_update_sk_buff_pa(skb);
-       skb_put(skb, sizeof(u32));
-
        /* Init val of Sleep Cookie */
-       *(u32 *)skb->data = FW_AWAKE_COOKIE;
+       *(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE;
 
        dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
-               *((u32 *)skb->data));
-
-       /* Save the sleep cookie */
-       card->sleep_cookie = skb;
+               *((u32 *)card->sleep_cookie_vbase));
 
        return 0;
 }
@@ -735,24 +754,57 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
 
        card = adapter->card;
 
-       if (card && card->sleep_cookie) {
-               dev_kfree_skb_any(card->sleep_cookie);
-               card->sleep_cookie = NULL;
+       if (card && card->sleep_cookie_vbase) {
+               pci_free_consistent(card->dev, sizeof(u32),
+                                   card->sleep_cookie_vbase,
+                                   card->sleep_cookie_pbase);
+               card->sleep_cookie_vbase = NULL;
        }
 
        return 0;
 }
 
+/* This function flushes the TX buffer descriptor ring
+ * This function defined as handler is also called while cleaning TXRX
+ * during disconnect/ bss stop.
+ */
+static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
+{
+       struct pcie_service_card *card = adapter->card;
+       u32 rdptr;
+
+       /* Read the TX ring read pointer set by firmware */
+       if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+               dev_err(adapter->dev,
+                       "Flush TXBD: failed to read REG_TXBD_RDPTR\n");
+               return -1;
+       }
+
+       if (!mwifiex_pcie_txbd_empty(card, rdptr)) {
+               card->txbd_flush = 1;
+               /* write pointer already set at last send
+                * send dnld-rdy intr again, wait for completion.
+                */
+               if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+                                     CPU_INTR_DNLD_RDY)) {
+                       dev_err(adapter->dev,
+                               "failed to assert dnld-rdy interrupt.\n");
+                       return -1;
+               }
+       }
+       return 0;
+}
+
 /*
- * This function sends data buffer to device
+ * This function unmaps and frees downloaded data buffer
  */
-static int
-mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
 {
+       const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD;
+       struct sk_buff *skb;
+       dma_addr_t buf_pa;
+       u32 wrdoneidx, rdptr, unmap_count = 0;
        struct pcie_service_card *card = adapter->card;
-       u32 wrindx, rdptr;
-       phys_addr_t *buf_pa;
-       __le16 *tmp;
 
        if (!mwifiex_pcie_ok_to_access_hw(adapter))
                mwifiex_pm_wakeup_card(adapter);
@@ -760,34 +812,112 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
        /* Read the TX ring read pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
                dev_err(adapter->dev,
-                       "SEND DATA: failed to read REG_TXBD_RDPTR\n");
+                       "SEND COMP: failed to read REG_TXBD_RDPTR\n");
                return -1;
        }
 
-       wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+       dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
+               card->txbd_rdptr, rdptr);
 
-       dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
-               card->txbd_wrptr);
-       if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
-                       (rdptr & MWIFIEX_TXBD_MASK)) ||
-           ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
-                       (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
-               struct sk_buff *skb_data;
+       /* free from previous txbd_rdptr to current txbd_rdptr */
+       while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) !=
+               (rdptr & MWIFIEX_TXBD_MASK)) ||
+              ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+               (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+               wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK;
+
+               skb = card->tx_buf_list[wrdoneidx];
+               if (skb) {
+                       dev_dbg(adapter->dev,
+                               "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
+                               skb, wrdoneidx);
+                       MWIFIEX_SKB_PACB(skb, &buf_pa);
+                       pci_unmap_single(card->dev, buf_pa, skb->len,
+                                        PCI_DMA_TODEVICE);
+
+                       unmap_count++;
+
+                       if (card->txbd_flush)
+                               mwifiex_write_data_complete(adapter, skb, 0,
+                                                           -1);
+                       else
+                               mwifiex_write_data_complete(adapter, skb, 0, 0);
+               }
+
+               card->tx_buf_list[wrdoneidx] = NULL;
+               card->txbd_ring[wrdoneidx]->paddr = 0;
+               card->rxbd_ring[wrdoneidx]->len = 0;
+               card->rxbd_ring[wrdoneidx]->flags = 0;
+               card->txbd_rdptr++;
+
+               if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs)
+                       card->txbd_rdptr = ((card->txbd_rdptr &
+                                           MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+                                           MWIFIEX_BD_FLAG_ROLLOVER_IND);
+       }
+
+       if (unmap_count)
+               adapter->data_sent = false;
+
+       if (card->txbd_flush) {
+               if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
+                    (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) &&
+                   ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+                    (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
+                       card->txbd_flush = 0;
+               else
+                       mwifiex_clean_pcie_ring_buf(adapter);
+       }
+
+       return 0;
+}
+
+/* This function sends data buffer to device. First 4 bytes of payload
+ * are filled with payload length and payload type. Then this payload
+ * is mapped to PCI device memory. Tx ring pointers are advanced accordingly.
+ * Download ready interrupt to FW is deffered if Tx ring is not full and
+ * additional payload can be accomodated.
+ */
+static int
+mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+                      struct mwifiex_tx_param *tx_param)
+{
+       struct pcie_service_card *card = adapter->card;
+       u32 wrindx;
+       int ret;
+       dma_addr_t buf_pa;
+       __le16 *tmp;
+
+       if (!(skb->data && skb->len)) {
+               dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n",
+                       __func__, skb->data, skb->len);
+               return -1;
+       }
+
+       if (!mwifiex_pcie_ok_to_access_hw(adapter))
+               mwifiex_pm_wakeup_card(adapter);
+
+       dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
+               card->txbd_rdptr, card->txbd_wrptr);
+       if (mwifiex_pcie_txbd_not_full(card)) {
                u8 *payload;
 
                adapter->data_sent = true;
-               skb_data = card->tx_buf_list[wrindx];
-               memcpy(skb_data->data, skb->data, skb->len);
-               payload = skb_data->data;
+               payload = skb->data;
                tmp = (__le16 *)&payload[0];
                *tmp = cpu_to_le16((u16)skb->len);
                tmp = (__le16 *)&payload[2];
                *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
-               skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
-               skb_trim(skb_data, skb->len);
-               buf_pa = MWIFIEX_SKB_PACB(skb_data);
-               card->txbd_ring[wrindx]->paddr = *buf_pa;
-               card->txbd_ring[wrindx]->len = (u16)skb_data->len;
+
+               if (mwifiex_map_pci_memory(adapter, skb, skb->len ,
+                                          PCI_DMA_TODEVICE))
+                       return -1;
+
+               wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
+               card->tx_buf_list[wrindx] = skb;
+               card->txbd_ring[wrindx]->paddr = buf_pa;
+               card->txbd_ring[wrindx]->len = (u16)skb->len;
                card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
                                                MWIFIEX_BD_FLAG_LAST_DESC;
 
@@ -802,19 +932,28 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                                      card->txbd_wrptr)) {
                        dev_err(adapter->dev,
                                "SEND DATA: failed to write REG_TXBD_WRPTR\n");
-                       return 0;
+                       ret = -1;
+                       goto done_unmap;
                }
-
-               /* Send the TX ready interrupt */
-               if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
-                                     CPU_INTR_DNLD_RDY)) {
-                       dev_err(adapter->dev,
-                               "SEND DATA: failed to assert door-bell intr\n");
-                       return -1;
+               if ((mwifiex_pcie_txbd_not_full(card)) &&
+                   tx_param->next_pkt_len) {
+                       /* have more packets and TxBD still can hold more */
+                       dev_dbg(adapter->dev,
+                               "SEND DATA: delay dnld-rdy interrupt.\n");
+                       adapter->data_sent = false;
+               } else {
+                       /* Send the TX ready interrupt */
+                       if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+                                             CPU_INTR_DNLD_RDY)) {
+                               dev_err(adapter->dev,
+                                       "SEND DATA: failed to assert dnld-rdy interrupt.\n");
+                               ret = -1;
+                               goto done_unmap;
+                       }
                }
                dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
                        "%#x> and sent packet to firmware successfully\n",
-                       rdptr, card->txbd_wrptr);
+                       card->txbd_rdptr, card->txbd_wrptr);
        } else {
                dev_dbg(adapter->dev,
                        "info: TX Ring full, can't send packets to fw\n");
@@ -827,7 +966,15 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                return -EBUSY;
        }
 
-       return 0;
+       return -EINPROGRESS;
+done_unmap:
+       MWIFIEX_SKB_PACB(skb, &buf_pa);
+       pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
+       card->tx_buf_list[wrindx] = NULL;
+       card->txbd_ring[wrindx]->paddr = 0;
+       card->txbd_ring[wrindx]->len = 0;
+       card->txbd_ring[wrindx]->flags = 0;
+       return ret;
 }
 
 /*
@@ -838,9 +985,13 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
        u32 wrptr, rd_index;
+       dma_addr_t buf_pa;
        int ret = 0;
        struct sk_buff *skb_tmp = NULL;
 
+       if (!mwifiex_pcie_ok_to_access_hw(adapter))
+               mwifiex_pm_wakeup_card(adapter);
+
        /* Read the RX ring Write pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
                dev_err(adapter->dev,
@@ -848,6 +999,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                ret = -1;
                goto done;
        }
+       card->rxbd_wrptr = wrptr;
 
        while (((wrptr & MWIFIEX_RXBD_MASK) !=
                (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
@@ -855,27 +1007,50 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
                struct sk_buff *skb_data;
                u16 rx_len;
+               __le16 pkt_len;
 
                rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
                skb_data = card->rx_buf_list[rd_index];
 
+               MWIFIEX_SKB_PACB(skb_data, &buf_pa);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
+                                PCI_DMA_FROMDEVICE);
+               card->rx_buf_list[rd_index] = NULL;
+
                /* Get data length from interface header -
-                  first byte is len, second byte is type */
-               rx_len = *((u16 *)skb_data->data);
+                * first 2 bytes for len, next 2 bytes is for type
+                */
+               pkt_len = *((__le16 *)skb_data->data);
+               rx_len = le16_to_cpu(pkt_len);
+               skb_put(skb_data, rx_len);
                dev_dbg(adapter->dev,
                        "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
                        card->rxbd_rdptr, wrptr, rx_len);
-               skb_tmp = dev_alloc_skb(rx_len);
+               skb_pull(skb_data, INTF_HEADER_LEN);
+               mwifiex_handle_rx_packet(adapter, skb_data);
+
+               skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
                if (!skb_tmp) {
-                       dev_dbg(adapter->dev,
-                               "info: Failed to alloc skb for RX\n");
-                       ret = -EBUSY;
-                       goto done;
+                       dev_err(adapter->dev,
+                               "Unable to allocate skb.\n");
+                       return -ENOMEM;
                }
 
-               skb_put(skb_tmp, rx_len);
+               if (mwifiex_map_pci_memory(adapter, skb_tmp,
+                                          MWIFIEX_RX_DATA_BUF_SIZE,
+                                          PCI_DMA_FROMDEVICE))
+                       return -1;
+
+               MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+
+               dev_dbg(adapter->dev,
+                       "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
+                       skb_tmp, rd_index);
+               card->rx_buf_list[rd_index] = skb_tmp;
+               card->rxbd_ring[rd_index]->paddr = buf_pa;
+               card->rxbd_ring[rd_index]->len = skb_tmp->len;
+               card->rxbd_ring[rd_index]->flags = 0;
 
-               memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
                if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
                                                        MWIFIEX_MAX_TXRX_BD) {
                        card->rxbd_rdptr = ((card->rxbd_rdptr &
@@ -903,12 +1078,10 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                }
                dev_dbg(adapter->dev,
                        "info: RECV DATA: Rcvd packet from fw successfully\n");
-               mwifiex_handle_rx_packet(adapter, skb_tmp);
+               card->rxbd_wrptr = wrptr;
        }
 
 done:
-       if (ret && skb_tmp)
-               dev_kfree_skb_any(skb_tmp);
        return ret;
 }
 
@@ -918,32 +1091,41 @@ done:
 static int
 mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 {
-       phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+       dma_addr_t buf_pa;
+       struct pcie_service_card *card = adapter->card;
 
-       if (!(skb->data && skb->len && *buf_pa)) {
+       if (!(skb->data && skb->len)) {
                dev_err(adapter->dev,
-                       "Invalid parameter in %s <%p, %#x:%x, %x>\n",
-                       __func__, skb->data, skb->len,
-                       (u32)*buf_pa, (u32)((u64)*buf_pa >> 32));
+                       "Invalid parameter in %s <%p. len %d>\n",
+                       __func__, skb->data, skb->len);
                return -1;
        }
 
+       if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE))
+               return -1;
+
+       MWIFIEX_SKB_PACB(skb, &buf_pa);
+
        /* Write the lower 32bits of the physical address to scratch
         * register 0 */
-       if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) {
+       if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)buf_pa)) {
                dev_err(adapter->dev,
                        "%s: failed to write download command to boot code.\n",
                        __func__);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+                                PCI_DMA_TODEVICE);
                return -1;
        }
 
        /* Write the upper 32bits of the physical address to scratch
         * register 1 */
        if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
-                             (u32)((u64)*buf_pa >> 32))) {
+                             (u32)((u64)buf_pa >> 32))) {
                dev_err(adapter->dev,
                        "%s: failed to write download command to boot code.\n",
                        __func__);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+                                PCI_DMA_TODEVICE);
                return -1;
        }
 
@@ -952,6 +1134,8 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                dev_err(adapter->dev,
                        "%s: failed to write command len to scratch reg 2\n",
                        __func__);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+                                PCI_DMA_TODEVICE);
                return -1;
        }
 
@@ -960,22 +1144,39 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                              CPU_INTR_DOOR_BELL)) {
                dev_err(adapter->dev,
                        "%s: failed to assert door-bell intr\n", __func__);
+               pci_unmap_single(card->dev, buf_pa,
+                                MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE);
                return -1;
        }
 
        return 0;
 }
 
-/*
- * This function downloads commands to the device
+/* This function init rx port in firmware which in turn enables to receive data
+ * from device before transmitting any packet.
+ */
+static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
+{
+       struct pcie_service_card *card = adapter->card;
+
+       /* Write the RX ring read pointer in to REG_RXBD_RDPTR */
+       if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr | 0)) {
+               dev_err(adapter->dev,
+                       "RECV DATA: failed to write REG_RXBD_RDPTR\n");
+               return -1;
+       }
+       return 0;
+}
+
+/* This function downloads commands to the device
  */
 static int
 mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 {
        struct pcie_service_card *card = adapter->card;
        int ret = 0;
-       phys_addr_t *cmd_buf_pa;
-       phys_addr_t *cmdrsp_buf_pa;
+       dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
+       u8 *payload = (u8 *)skb->data;
 
        if (!(skb->data && skb->len)) {
                dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
@@ -990,17 +1191,18 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                return -EBUSY;
        }
 
-       /* Make sure a command buffer is available */
-       if (!card->cmd_buf) {
-               dev_err(adapter->dev, "Command buffer not available\n");
-               return -EBUSY;
-       }
+       if (!mwifiex_pcie_ok_to_access_hw(adapter))
+               mwifiex_pm_wakeup_card(adapter);
 
        adapter->cmd_sent = true;
-       /* Copy the given skb in to DMA accessable shared buffer */
-       skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len);
-       skb_trim(card->cmd_buf, skb->len);
-       memcpy(card->cmd_buf->data, skb->data, skb->len);
+
+       *(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len);
+       *(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD);
+
+       if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE))
+               return -1;
+
+       card->cmd_buf = skb;
 
        /* To send a command, the driver will:
                1. Write the 64bit physical address of the data buffer to
@@ -1013,11 +1215,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
        */
 
        if (card->cmdrsp_buf) {
-               cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf);
+               MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa);
                /* Write the lower 32bits of the cmdrsp buffer physical
                   address */
                if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
-                                     (u32)*cmdrsp_buf_pa)) {
+                                     (u32)cmdrsp_buf_pa)) {
                        dev_err(adapter->dev,
                                "Failed to write download cmd to boot code.\n");
                        ret = -1;
@@ -1026,7 +1228,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                /* Write the upper 32bits of the cmdrsp buffer physical
                   address */
                if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
-                                     (u32)((u64)*cmdrsp_buf_pa >> 32))) {
+                                     (u32)((u64)cmdrsp_buf_pa >> 32))) {
                        dev_err(adapter->dev,
                                "Failed to write download cmd to boot code.\n");
                        ret = -1;
@@ -1034,9 +1236,9 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                }
        }
 
-       cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf);
+       MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa);
        /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
-       if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)*cmd_buf_pa)) {
+       if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)cmd_buf_pa)) {
                dev_err(adapter->dev,
                        "Failed to write download cmd to boot code.\n");
                ret = -1;
@@ -1044,7 +1246,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
        }
        /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
        if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
-                             (u32)((u64)*cmd_buf_pa >> 32))) {
+                             (u32)((u64)cmd_buf_pa >> 32))) {
                dev_err(adapter->dev,
                        "Failed to write download cmd to boot code.\n");
                ret = -1;
@@ -1083,11 +1285,22 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        struct sk_buff *skb = card->cmdrsp_buf;
        int count = 0;
+       u16 rx_len;
+       __le16 pkt_len;
+       dma_addr_t buf_pa;
 
        dev_dbg(adapter->dev, "info: Rx CMD Response\n");
 
+       MWIFIEX_SKB_PACB(skb, &buf_pa);
+       pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+                        PCI_DMA_FROMDEVICE);
+
+       pkt_len = *((__le16 *)skb->data);
+       rx_len = le16_to_cpu(pkt_len);
+       skb_trim(skb, rx_len);
+       skb_pull(skb, INTF_HEADER_LEN);
+
        if (!adapter->curr_cmd) {
-               skb_pull(skb, INTF_HEADER_LEN);
                if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
                        mwifiex_process_sleep_confirm_resp(adapter, skb->data,
                                                           skb->len);
@@ -1100,9 +1313,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
                }
                memcpy(adapter->upld_buf, skb->data,
                       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
-               skb_push(skb, INTF_HEADER_LEN);
+               if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+                                          PCI_DMA_FROMDEVICE))
+                       return -1;
+
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
        } else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
-               skb_pull(skb, INTF_HEADER_LEN);
                adapter->curr_cmd->resp_skb = skb;
                adapter->cmd_resp_received = true;
                /* Take the pointer and set it to CMD node and will
@@ -1136,10 +1352,23 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
                                        struct sk_buff *skb)
 {
        struct pcie_service_card *card = adapter->card;
+       dma_addr_t buf_pa;
+       struct sk_buff *skb_tmp;
 
        if (skb) {
                card->cmdrsp_buf = skb;
                skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+               if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+                                          PCI_DMA_FROMDEVICE))
+                       return -1;
+       }
+
+       skb_tmp = card->cmd_buf;
+       if (skb_tmp) {
+               MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+                                PCI_DMA_FROMDEVICE);
+               card->cmd_buf = NULL;
        }
 
        return 0;
@@ -1153,6 +1382,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
        u32 wrptr, event;
+       dma_addr_t buf_pa;
+
+       if (!mwifiex_pcie_ok_to_access_hw(adapter))
+               mwifiex_pm_wakeup_card(adapter);
 
        if (adapter->event_received) {
                dev_dbg(adapter->dev, "info: Event being processed, "
@@ -1184,6 +1417,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
 
                dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
                skb_cmd = card->evt_buf_list[rdptr];
+               MWIFIEX_SKB_PACB(skb_cmd, &buf_pa);
+               pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE,
+                                PCI_DMA_FROMDEVICE);
+
                /* Take the pointer and set it to event pointer in adapter
                   and will return back after event handling callback */
                card->evt_buf_list[rdptr] = NULL;
@@ -1228,7 +1465,7 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
        int ret = 0;
        u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
        u32 wrptr;
-       phys_addr_t *buf_pa;
+       dma_addr_t buf_pa;
 
        if (!skb)
                return 0;
@@ -1248,9 +1485,14 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
 
        if (!card->evt_buf_list[rdptr]) {
                skb_push(skb, INTF_HEADER_LEN);
+               if (mwifiex_map_pci_memory(adapter, skb,
+                                          MAX_EVENT_SIZE,
+                                          PCI_DMA_FROMDEVICE))
+                       return -1;
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
                card->evt_buf_list[rdptr] = skb;
-               buf_pa = MWIFIEX_SKB_PACB(skb);
-               card->evtbd_ring[rdptr]->paddr = *buf_pa;
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
+               card->evtbd_ring[rdptr]->paddr = buf_pa;
                card->evtbd_ring[rdptr]->len = (u16)skb->len;
                card->evtbd_ring[rdptr]->flags = 0;
                skb = NULL;
@@ -1299,11 +1541,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
        struct sk_buff *skb;
        u32 txlen, tx_blocks = 0, tries, len;
        u32 block_retry_cnt = 0;
-
-       if (!adapter) {
-               pr_err("adapter structure is not valid\n");
-               return -1;
-       }
+       dma_addr_t buf_pa;
+       struct pcie_service_card *card = adapter->card;
 
        if (!firmware || !firmware_len) {
                dev_err(adapter->dev,
@@ -1325,7 +1564,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                ret = -ENOMEM;
                goto done;
        }
-       mwifiex_update_sk_buff_pa(skb);
 
        /* Perform firmware data transfer */
        do {
@@ -1400,6 +1638,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                        ret = -1;
                        goto done;
                }
+
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
+
                /* Wait for the command done interrupt */
                do {
                        if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
@@ -1407,11 +1648,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                                dev_err(adapter->dev, "%s: Failed to read "
                                        "interrupt status during fw dnld.\n",
                                        __func__);
+                               pci_unmap_single(card->dev, buf_pa, skb->len,
+                                                PCI_DMA_TODEVICE);
                                ret = -1;
                                goto done;
                        }
                } while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
                         CPU_INTR_DOOR_BELL);
+
+               pci_unmap_single(card->dev, buf_pa, skb->len,
+                                PCI_DMA_TODEVICE);
+
                offset += txlen;
        } while (true);
 
@@ -1594,39 +1841,40 @@ exit:
 static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
 {
        int ret;
-       u32 pcie_ireg = 0;
+       u32 pcie_ireg;
        unsigned long flags;
 
        spin_lock_irqsave(&adapter->int_lock, flags);
        /* Clear out unused interrupts */
-       adapter->int_status &= HOST_INTR_MASK;
+       pcie_ireg = adapter->int_status;
+       adapter->int_status = 0;
        spin_unlock_irqrestore(&adapter->int_lock, flags);
 
-       while (adapter->int_status & HOST_INTR_MASK) {
-               if (adapter->int_status & HOST_INTR_DNLD_DONE) {
-                       adapter->int_status &= ~HOST_INTR_DNLD_DONE;
-                       if (adapter->data_sent) {
-                               dev_dbg(adapter->dev, "info: DATA sent intr\n");
-                               adapter->data_sent = false;
-                       }
+       while (pcie_ireg & HOST_INTR_MASK) {
+               if (pcie_ireg & HOST_INTR_DNLD_DONE) {
+                       pcie_ireg &= ~HOST_INTR_DNLD_DONE;
+                       dev_dbg(adapter->dev, "info: TX DNLD Done\n");
+                       ret = mwifiex_pcie_send_data_complete(adapter);
+                       if (ret)
+                               return ret;
                }
-               if (adapter->int_status & HOST_INTR_UPLD_RDY) {
-                       adapter->int_status &= ~HOST_INTR_UPLD_RDY;
+               if (pcie_ireg & HOST_INTR_UPLD_RDY) {
+                       pcie_ireg &= ~HOST_INTR_UPLD_RDY;
                        dev_dbg(adapter->dev, "info: Rx DATA\n");
                        ret = mwifiex_pcie_process_recv_data(adapter);
                        if (ret)
                                return ret;
                }
-               if (adapter->int_status & HOST_INTR_EVENT_RDY) {
-                       adapter->int_status &= ~HOST_INTR_EVENT_RDY;
+               if (pcie_ireg & HOST_INTR_EVENT_RDY) {
+                       pcie_ireg &= ~HOST_INTR_EVENT_RDY;
                        dev_dbg(adapter->dev, "info: Rx EVENT\n");
                        ret = mwifiex_pcie_process_event_ready(adapter);
                        if (ret)
                                return ret;
                }
 
-               if (adapter->int_status & HOST_INTR_CMD_DONE) {
-                       adapter->int_status &= ~HOST_INTR_CMD_DONE;
+               if (pcie_ireg & HOST_INTR_CMD_DONE) {
+                       pcie_ireg &= ~HOST_INTR_CMD_DONE;
                        if (adapter->cmd_sent) {
                                dev_dbg(adapter->dev,
                                        "info: CMD sent Interrupt\n");
@@ -1654,8 +1902,6 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
                                                 "Write register failed\n");
                                        return -1;
                                }
-                               adapter->int_status |= pcie_ireg;
-                               adapter->int_status &= HOST_INTR_MASK;
                        }
 
                }
@@ -1687,7 +1933,7 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
        }
 
        if (type == MWIFIEX_TYPE_DATA)
-               return mwifiex_pcie_send_data(adapter, skb);
+               return mwifiex_pcie_send_data(adapter, skb, tx_param);
        else if (type == MWIFIEX_TYPE_CMD)
                return mwifiex_pcie_send_cmd(adapter, skb);
 
@@ -1814,15 +2060,8 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        struct pci_dev *pdev = card->dev;
 
-       mwifiex_pcie_delete_sleep_cookie_buf(adapter);
-       mwifiex_pcie_delete_cmdrsp_buf(adapter);
-       mwifiex_pcie_delete_evtbd_ring(adapter);
-       mwifiex_pcie_delete_rxbd_ring(adapter);
-       mwifiex_pcie_delete_txbd_ring(adapter);
-       card->cmdrsp_buf = NULL;
-
-       dev_dbg(adapter->dev, "Clearing driver ready signature\n");
        if (user_rmmod) {
+               dev_dbg(adapter->dev, "Clearing driver ready signature\n");
                if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
                        dev_err(adapter->dev,
                                "Failed to write driver not-ready signature\n");
@@ -1879,6 +2118,13 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
        if (card) {
                dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
                free_irq(card->dev->irq, card->dev);
+
+               mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+               mwifiex_pcie_delete_cmdrsp_buf(adapter);
+               mwifiex_pcie_delete_evtbd_ring(adapter);
+               mwifiex_pcie_delete_rxbd_ring(adapter);
+               mwifiex_pcie_delete_txbd_ring(adapter);
+               card->cmdrsp_buf = NULL;
        }
 }
 
@@ -1900,6 +2146,8 @@ static struct mwifiex_if_ops pcie_ops = {
        .event_complete =               mwifiex_pcie_event_complete,
        .update_mp_end_port =           NULL,
        .cleanup_mpa_buf =              NULL,
+       .init_fw_port =                 mwifiex_pcie_init_fw_port,
+       .clean_pcie_ring =              mwifiex_clean_pcie_ring_buf,
 };
 
 /*
index 2f218f9a3fd3efea52e8038345a326bfb7341243..37eeb2ca6b298654adc603dc9be0e3deca27a9f1 100644 (file)
@@ -114,11 +114,12 @@ struct pcie_service_card {
        struct pci_dev *dev;
        struct mwifiex_adapter *adapter;
 
+       u8 txbd_flush;
        u32 txbd_wrptr;
        u32 txbd_rdptr;
        u32 txbd_ring_size;
        u8 *txbd_ring_vbase;
-       phys_addr_t txbd_ring_pbase;
+       dma_addr_t txbd_ring_pbase;
        struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD];
        struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
 
@@ -126,7 +127,7 @@ struct pcie_service_card {
        u32 rxbd_rdptr;
        u32 rxbd_ring_size;
        u8 *rxbd_ring_vbase;
-       phys_addr_t rxbd_ring_pbase;
+       dma_addr_t rxbd_ring_pbase;
        struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
        struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
 
@@ -134,15 +135,39 @@ struct pcie_service_card {
        u32 evtbd_rdptr;
        u32 evtbd_ring_size;
        u8 *evtbd_ring_vbase;
-       phys_addr_t evtbd_ring_pbase;
+       dma_addr_t evtbd_ring_pbase;
        struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD];
        struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
 
        struct sk_buff *cmd_buf;
        struct sk_buff *cmdrsp_buf;
-       struct sk_buff *sleep_cookie;
+       u8 *sleep_cookie_vbase;
+       dma_addr_t sleep_cookie_pbase;
        void __iomem *pci_mmap;
        void __iomem *pci_mmap1;
 };
 
+static inline int
+mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
+{
+       if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
+                       (rdptr & MWIFIEX_TXBD_MASK)) &&
+           ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+                       (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
+               return 1;
+
+       return 0;
+}
+
+static inline int
+mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
+{
+       if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
+            (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) ||
+           ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+            (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
+               return 1;
+
+       return 0;
+}
 #endif /* _MWIFIEX_PCIE_H */
index 5d87195390f863a9492aadaa9ea1d51d6ba8ae8e..c4607859d59d5a45fd58da58e8491e14be5275ea 100644 (file)
@@ -931,7 +931,6 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
        struct host_cmd_ds_pcie_details *host_spec =
                                        &cmd->params.pcie_host_spec;
        struct pcie_service_card *card = priv->adapter->card;
-       phys_addr_t *buf_pa;
 
        cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
        cmd->size = cpu_to_le16(sizeof(struct
@@ -953,10 +952,11 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
        host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase);
        host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32);
        host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD;
-       if (card->sleep_cookie) {
-               buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie);
-               host_spec->sleep_cookie_addr_lo = (u32) *buf_pa;
-               host_spec->sleep_cookie_addr_hi = (u32) (((u64)*buf_pa) >> 32);
+       if (card->sleep_cookie_vbase) {
+               host_spec->sleep_cookie_addr_lo =
+                                               (u32)(card->sleep_cookie_pbase);
+               host_spec->sleep_cookie_addr_hi =
+                                (u32)(((u64)(card->sleep_cookie_pbase)) >> 32);
                dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n",
                        host_spec->sleep_cookie_addr_lo);
        }
index 8c80024c30ff6345399d53e7132bed310a6c12a6..296faec143657bde52c6304f429f4b0b231221a3 100644 (file)
@@ -117,14 +117,16 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
                dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
                break;
        case -1:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
                        ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb, 0, ret);
index 8dd72240f162d9786e4fac374fdf7144307b0ee8..6e76a15a89501a7aa6cacde72aee43cd10612f1d 100644 (file)
@@ -219,6 +219,7 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
        config->rts_threshold = 0x7FFF;
        config->frag_threshold = 0x7FFF;
        config->retry_limit = 0x7F;
+       config->qos_info = 0xFF;
 }
 
 /* This function parses BSS related parameters from structure
@@ -297,6 +298,38 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
        return;
 }
 
+/* This function parses WMM related parameters from cfg80211_ap_settings
+ * structure and updates bss_config structure.
+ */
+void
+mwifiex_set_wmm_params(struct mwifiex_private *priv,
+                      struct mwifiex_uap_bss_param *bss_cfg,
+                      struct cfg80211_ap_settings *params)
+{
+       const u8 *vendor_ie;
+       struct ieee_types_header *wmm_ie;
+       u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02};
+
+       vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+                                           WLAN_OUI_TYPE_MICROSOFT_WMM,
+                                           params->beacon.tail,
+                                           params->beacon.tail_len);
+       if (vendor_ie) {
+               wmm_ie = (struct ieee_types_header *)vendor_ie;
+               memcpy(&bss_cfg->wmm_info, wmm_ie + 1,
+                      sizeof(bss_cfg->wmm_info));
+               priv->wmm_enabled = 1;
+       } else {
+               memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info));
+               memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui));
+               bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE;
+               bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION;
+               priv->wmm_enabled = 0;
+       }
+
+       bss_cfg->qos_info = 0x00;
+       return;
+}
 /* This function parses BSS related parameters from structure
  * and prepares TLVs specific to WEP encryption.
  * These TLVs are appended to command buffer.
@@ -354,6 +387,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        struct host_cmd_tlv_rates *tlv_rates;
        struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
        struct mwifiex_ie_types_htcap *htcap;
+       struct mwifiex_ie_types_wmmcap *wmm_cap;
        struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
        int i;
        u16 cmd_size = *param_size;
@@ -507,6 +541,16 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
                tlv += sizeof(struct mwifiex_ie_types_htcap);
        }
 
+       if (bss_cfg->wmm_info.qos_info != 0xFF) {
+               wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv;
+               wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC);
+               wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info));
+               memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info,
+                      sizeof(wmm_cap->wmm_info));
+               cmd_size += sizeof(struct mwifiex_ie_types_wmmcap);
+               tlv += sizeof(struct mwifiex_ie_types_wmmcap);
+       }
+
        if (bss_cfg->sta_ao_timer) {
                ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
                ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
index 63ac9f2d11ae2fb15af3324175b522f36a2792bc..5d4a10a8a005ef1e853d272866f47c3c4596d7a2 100644 (file)
@@ -786,21 +786,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        return 0;
 }
 
-/* This function reads one block of firmware data. */
-static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter,
-                              u32 offset, u32 len, u8 *buf)
-{
-       if (!buf || !len)
-               return -1;
-
-       if (offset + len > adapter->firmware->size)
-               return -1;
-
-       memcpy(buf, adapter->firmware->data + offset, len);
-
-       return 0;
-}
-
 static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                                    struct mwifiex_fw_image *fw)
 {
@@ -836,23 +821,14 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                        dlen = 0;
                } else {
                        /* copy the header of the fw_data to get the length */
-                       if (firmware)
-                               memcpy(&fwdata->fw_hdr, &firmware[tlen],
-                                      sizeof(struct fw_header));
-                       else
-                               mwifiex_get_fw_data(adapter, tlen,
-                                                   sizeof(struct fw_header),
-                                                   (u8 *)&fwdata->fw_hdr);
+                       memcpy(&fwdata->fw_hdr, &firmware[tlen],
+                              sizeof(struct fw_header));
 
                        dlen = le32_to_cpu(fwdata->fw_hdr.data_len);
                        dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd);
                        tlen += sizeof(struct fw_header);
 
-                       if (firmware)
-                               memcpy(fwdata->data, &firmware[tlen], dlen);
-                       else
-                               mwifiex_get_fw_data(adapter, tlen, dlen,
-                                                   (u8 *)fwdata->data);
+                       memcpy(fwdata->data, &firmware[tlen], dlen);
 
                        fwdata->seq_num = cpu_to_le32(fw_seqnum);
                        tlen += dlen;
index f6d36b9654a03fa1e23a7f867ac0b6eec62dee14..cb2d0582bd363a42a55c23281eab163fdb05856e 100644 (file)
 
 static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
 {
-       return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t));
+       return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t));
 }
 
 static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
 {
-       return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t));
+       return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t));
 }
 
-static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb)
+static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, dma_addr_t *buf_pa)
 {
-       return (phys_addr_t *)skb->cb;
+       memcpy(buf_pa, skb->cb, sizeof(dma_addr_t));
 }
 #endif /* !_MWIFIEX_UTIL_H_ */
index 818f871ae987fc4944741562e18fca47b2fdd156..135d96df2063a976ca107841b6d4f494abb1702a 100644 (file)
@@ -568,6 +568,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
        mwifiex_wmm_delete_all_ralist(priv);
        memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
 
+       if (priv->adapter->if_ops.clean_pcie_ring)
+               priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 }
 
@@ -1206,13 +1208,15 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                                       ra_list_flags);
                break;
        case -1:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
        default:
                break;
        }
index 83564d36e801884bfb6d9c566653542dbe60cee4..224cf917744a7d9a1f9c02aea8f1dde473645b20 100644 (file)
@@ -101,6 +101,18 @@ MODULE_PARM_DESC(ap_mode_default,
 #define MWL8K_MAX_TX_QUEUES    (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES)
 #define mwl8k_tx_queues(priv)  (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues)
 
+/* txpriorities are mapped with hw queues.
+ * Each hw queue has a txpriority.
+ */
+#define TOTAL_HW_TX_QUEUES     8
+
+/* Each HW queue can have one AMPDU stream.
+ * But, because one of the hw queue is reserved,
+ * maximum AMPDU queues that can be created are
+ * one short of total tx queues.
+ */
+#define MWL8K_NUM_AMPDU_STREAMS        (TOTAL_HW_TX_QUEUES - 1)
+
 struct rxd_ops {
        int rxd_size;
        void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
@@ -160,7 +172,6 @@ struct mwl8k_ampdu_stream {
        u8 tid;
        u8 state;
        u8 idx;
-       u8 txq_idx; /* index of this stream in priv->txq */
 };
 
 struct mwl8k_priv {
@@ -202,6 +213,8 @@ struct mwl8k_priv {
        int fw_mutex_depth;
        struct completion *hostcmd_wait;
 
+       atomic_t watchdog_event_pending;
+
        /* lock held over TX and TX reap */
        spinlock_t tx_lock;
 
@@ -1516,6 +1529,9 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
                        return -EBUSY;
        }
 
+       if (atomic_read(&priv->watchdog_event_pending))
+               return 0;
+
        /*
         * The TX queues are stopped at this point, so this test
         * doesn't need to take ->tx_lock.
@@ -1537,6 +1553,14 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
                spin_unlock_bh(&priv->tx_lock);
                timeout = wait_for_completion_timeout(&tx_wait,
                            msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS));
+
+               if (atomic_read(&priv->watchdog_event_pending)) {
+                       spin_lock_bh(&priv->tx_lock);
+                       priv->tx_wait = NULL;
+                       spin_unlock_bh(&priv->tx_lock);
+                       return 0;
+               }
+
                spin_lock_bh(&priv->tx_lock);
 
                if (timeout) {
@@ -1564,6 +1588,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
 
                rc = -ETIMEDOUT;
        }
+       priv->tx_wait = NULL;
        spin_unlock_bh(&priv->tx_lock);
 
        return rc;
@@ -1734,14 +1759,13 @@ mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid)
        struct mwl8k_priv *priv = hw->priv;
        int i;
 
-       for (i = 0; i < priv->num_ampdu_queues; i++) {
+       for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
                stream = &priv->ampdu[i];
                if (stream->state == AMPDU_NO_STREAM) {
                        stream->sta = sta;
                        stream->state = AMPDU_STREAM_NEW;
                        stream->tid = tid;
                        stream->idx = i;
-                       stream->txq_idx = MWL8K_TX_WMM_QUEUES + i;
                        wiphy_debug(hw->wiphy, "Added a new stream for %pM %d",
                                    sta->addr, tid);
                        return stream;
@@ -1782,7 +1806,7 @@ mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid)
        struct mwl8k_priv *priv = hw->priv;
        int i;
 
-       for (i = 0 ; i < priv->num_ampdu_queues; i++) {
+       for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
                struct mwl8k_ampdu_stream *stream;
                stream = &priv->ampdu[i];
                if (stream->state == AMPDU_NO_STREAM)
@@ -1829,6 +1853,13 @@ static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid)
                tx_stats->pkts++;
 }
 
+/* The hardware ampdu queues start from 5.
+ * txpriorities for ampdu queues are
+ * 5 6 7 0 1 2 3 4 ie., queue 5 is highest
+ * and queue 3 is lowest (queue 4 is reserved)
+ */
+#define BA_QUEUE               5
+
 static void
 mwl8k_txq_xmit(struct ieee80211_hw *hw,
               int index,
@@ -1928,8 +1959,13 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
                stream = mwl8k_lookup_stream(hw, sta->addr, tid);
                if (stream != NULL) {
                        if (stream->state == AMPDU_STREAM_ACTIVE) {
-                               txpriority = stream->txq_idx;
-                               index = stream->txq_idx;
+                               WARN_ON(!(qos & MWL8K_QOS_ACK_POLICY_BLOCKACK));
+                               txpriority = (BA_QUEUE + stream->idx) %
+                                            TOTAL_HW_TX_QUEUES;
+                               if (stream->idx <= 1)
+                                       index = stream->idx +
+                                               MWL8K_TX_WMM_QUEUES;
+
                        } else if (stream->state == AMPDU_STREAM_NEW) {
                                /* We get here if the driver sends us packets
                                 * after we've initiated a stream, but before
@@ -1971,6 +2007,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
                        }
                }
                spin_unlock(&priv->stream_lock);
+       } else {
+               qos &= ~MWL8K_QOS_ACK_POLICY_MASK;
+               qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
        }
 
        dma = pci_map_single(priv->pdev, skb->data,
@@ -3578,7 +3617,11 @@ static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap)
        return rc;
 }
 
-#define INVALID_BA     0xAA
+#define MWL8K_WMM_QUEUE_NUMBER 3
+
+static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
+                            u8 idx);
+
 static void mwl8k_watchdog_ba_events(struct work_struct *work)
 {
        int rc;
@@ -3586,24 +3629,41 @@ static void mwl8k_watchdog_ba_events(struct work_struct *work)
        struct mwl8k_ampdu_stream *streams;
        struct mwl8k_priv *priv =
                container_of(work, struct mwl8k_priv, watchdog_ba_handle);
+       struct ieee80211_hw *hw = priv->hw;
+       int i;
+       u32 status = 0;
+
+       mwl8k_fw_lock(hw);
 
        rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap);
        if (rc)
-               return;
+               goto done;
 
-       if (bitmap == INVALID_BA)
-               return;
+       spin_lock(&priv->stream_lock);
 
        /* the bitmap is the hw queue number.  Map it to the ampdu queue. */
-       stream_index = bitmap - MWL8K_TX_WMM_QUEUES;
-
-       BUG_ON(stream_index >= priv->num_ampdu_queues);
-
-       streams = &priv->ampdu[stream_index];
-
-       if (streams->state == AMPDU_STREAM_ACTIVE)
-               ieee80211_stop_tx_ba_session(streams->sta, streams->tid);
+       for (i = 0; i < TOTAL_HW_TX_QUEUES; i++) {
+               if (bitmap & (1 << i)) {
+                       stream_index = (i + MWL8K_WMM_QUEUE_NUMBER) %
+                                      TOTAL_HW_TX_QUEUES;
+                       streams = &priv->ampdu[stream_index];
+                       if (streams->state == AMPDU_STREAM_ACTIVE) {
+                               ieee80211_stop_tx_ba_session(streams->sta,
+                                                            streams->tid);
+                               spin_unlock(&priv->stream_lock);
+                               mwl8k_destroy_ba(hw, stream_index);
+                               spin_lock(&priv->stream_lock);
+                       }
+               }
+       }
 
+       spin_unlock(&priv->stream_lock);
+done:
+       atomic_dec(&priv->watchdog_event_pending);
+       status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+       iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG),
+                 priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+       mwl8k_fw_unlock(hw);
        return;
 }
 
@@ -3763,7 +3823,7 @@ mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
 }
 
 static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
-                            struct mwl8k_ampdu_stream *stream)
+                            u8 idx)
 {
        struct mwl8k_cmd_bastream *cmd;
 
@@ -3775,10 +3835,10 @@ static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
        cmd->action = cpu_to_le32(MWL8K_BA_DESTROY);
 
-       cmd->destroy_params.ba_context = cpu_to_le32(stream->idx);
+       cmd->destroy_params.ba_context = cpu_to_le32(idx);
        mwl8k_post_cmd(hw, &cmd->header);
 
-       wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx);
+       wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", idx);
 
        kfree(cmd);
 }
@@ -3875,7 +3935,30 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif, u8 *addr)
 {
        struct mwl8k_cmd_set_new_stn *cmd;
-       int rc;
+       struct mwl8k_priv *priv = hw->priv;
+       int rc, i;
+       u8 idx;
+
+       spin_lock(&priv->stream_lock);
+       /* Destroy any active ampdu streams for this sta */
+       for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
+               struct mwl8k_ampdu_stream *s;
+               s = &priv->ampdu[i];
+               if (s->state != AMPDU_NO_STREAM) {
+                       if (memcmp(s->sta->addr, addr, ETH_ALEN) == 0) {
+                               if (s->state == AMPDU_STREAM_ACTIVE) {
+                                       idx = s->idx;
+                                       spin_unlock(&priv->stream_lock);
+                                       mwl8k_destroy_ba(hw, idx);
+                                       spin_lock(&priv->stream_lock);
+                               } else if (s->state == AMPDU_STREAM_NEW) {
+                                       mwl8k_remove_stream(hw, s);
+                               }
+                       }
+               }
+       }
+
+       spin_unlock(&priv->stream_lock);
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
@@ -4303,6 +4386,10 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
        }
 
        if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
+               iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG,
+                         priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+
+               atomic_inc(&priv->watchdog_event_pending);
                status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
                ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
        }
@@ -4446,6 +4533,8 @@ static int mwl8k_start(struct ieee80211_hw *hw)
                priv->irq = -1;
                tasklet_disable(&priv->poll_tx_task);
                tasklet_disable(&priv->poll_rx_task);
+       } else {
+               ieee80211_wake_queues(hw);
        }
 
        return rc;
@@ -5094,7 +5183,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        int i, rc = 0;
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_ampdu_stream *stream;
-       u8 *addr = sta->addr;
+       u8 *addr = sta->addr, idx;
        struct mwl8k_sta *sta_info = MWL8K_STA(sta);
 
        if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
@@ -5172,11 +5261,14 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                }
                ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                if (stream) {
                        if (stream->state == AMPDU_STREAM_ACTIVE) {
+                               idx = stream->idx;
                                spin_unlock(&priv->stream_lock);
-                               mwl8k_destroy_ba(hw, stream);
+                               mwl8k_destroy_ba(hw, idx);
                                spin_lock(&priv->stream_lock);
                        }
                        mwl8k_remove_stream(hw, stream);
@@ -5192,8 +5284,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                if (!rc)
                        stream->state = AMPDU_STREAM_ACTIVE;
                else {
+                       idx = stream->idx;
                        spin_unlock(&priv->stream_lock);
-                       mwl8k_destroy_ba(hw, stream);
+                       mwl8k_destroy_ba(hw, idx);
                        spin_lock(&priv->stream_lock);
                        wiphy_debug(hw->wiphy,
                                "Failed adding stream for sta %pM tid %d\n",
@@ -5256,7 +5349,7 @@ enum {
        MWL8366,
 };
 
-#define MWL8K_8366_AP_FW_API 2
+#define MWL8K_8366_AP_FW_API 3
 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
 #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
 
@@ -5464,6 +5557,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
                if (priv->rxd_ops == NULL) {
                        wiphy_err(hw->wiphy,
                                  "Driver does not have AP firmware image support for this hardware\n");
+                       rc = -ENOENT;
                        goto err_stop_firmware;
                }
        } else {
@@ -5473,6 +5567,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
        priv->sniffer_enabled = false;
        priv->wmm_enabled = false;
        priv->pending_tx_pkts = 0;
+       atomic_set(&priv->watchdog_event_pending, 0);
 
        rc = mwl8k_rxq_init(hw, 0);
        if (rc)
@@ -5809,6 +5904,7 @@ static int mwl8k_probe(struct pci_dev *pdev,
        priv->sram = pci_iomap(pdev, 0, 0x10000);
        if (priv->sram == NULL) {
                wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
+               rc = -EIO;
                goto err_iounmap;
        }
 
@@ -5821,6 +5917,7 @@ static int mwl8k_probe(struct pci_dev *pdev,
                priv->regs = pci_iomap(pdev, 2, 0x10000);
                if (priv->regs == NULL) {
                        wiphy_err(hw->wiphy, "Cannot map device registers\n");
+                       rc = -EIO;
                        goto err_iounmap;
                }
        }
index 88e3ad2d1db8dea4d5e2fcdee52285e399644bcd..1e802f82ae49ab746ee670d05f4ed56143f1d43b 100644 (file)
@@ -2290,7 +2290,6 @@ int orinoco_if_add(struct orinoco_private *priv,
        netif_carrier_off(dev);
 
        memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
-       memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
 
        dev->base_addr = base_addr;
        dev->irq = irq;
index 933e5d9419373529bc2b5428c34e9ea1c49f7331..57e3af8ebb4b39622450d1fbee0742b39ab5a0a3 100644 (file)
@@ -559,6 +559,7 @@ static int p54p_probe(struct pci_dev *pdev,
        mem_len = pci_resource_len(pdev, 0);
        if (mem_len < sizeof(struct p54p_csr)) {
                dev_err(&pdev->dev, "Too short PCI resources\n");
+               err = -ENODEV;
                goto err_disable_dev;
        }
 
@@ -568,8 +569,10 @@ static int p54p_probe(struct pci_dev *pdev,
                goto err_disable_dev;
        }
 
-       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
-           pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (!err)
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (err) {
                dev_err(&pdev->dev, "No suitable DMA available\n");
                goto err_free_reg;
        }
index 4e44b1af119aae45a1bf5956dd80fc283736bd78..1c22b81e6ef35e30f86afc994445ff66ef4f7c36 100644 (file)
@@ -1503,6 +1503,7 @@ static int prism54_get_auth(struct net_device *ndev,
                        case DOT11_AUTH_BOTH:
                        case DOT11_AUTH_SK:
                                param->value = IW_AUTH_ALG_SHARED_KEY;
+                               break;
                        case DOT11_AUTH_NONE:
                        default:
                                param->value = 0;
index 598ca1cafb958cc258867e8970bc2ed506472878..e7cf37f550d10dc70b3aa0b4ab9922325154d18c 100644 (file)
@@ -1107,12 +1107,15 @@ static int ray_get_essid(struct net_device *dev, struct iw_request_info *info,
                         union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
+       UCHAR tmp[IW_ESSID_MAX_SIZE + 1];
 
        /* Get the essid that was set */
        memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+       memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+       tmp[IW_ESSID_MAX_SIZE] = '\0';
 
        /* Push it out ! */
-       wrqu->essid.length = strlen(extra);
+       wrqu->essid.length = strlen(tmp);
        wrqu->essid.flags = 1;  /* active */
 
        return 0;
@@ -1842,6 +1845,8 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
        UCHAR tmp;
        UCHAR cmd;
        UCHAR status;
+       UCHAR memtmp[ESSID_SIZE + 1];
+
 
        if (dev == NULL)        /* Note that we want interrupts with dev->start == 0 */
                return IRQ_NONE;
@@ -1901,17 +1906,21 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
                        break;
                case CCS_START_NETWORK:
                case CCS_JOIN_NETWORK:
+                       memcpy(memtmp, local->sparm.b4.a_current_ess_id,
+                                                               ESSID_SIZE);
+                       memtmp[ESSID_SIZE] = '\0';
+
                        if (status == CCS_COMMAND_COMPLETE) {
                                if (readb
                                    (&pccs->var.start_network.net_initiated) ==
                                    1) {
                                        dev_dbg(&link->dev,
                                              "ray_cs interrupt network \"%s\" started\n",
-                                             local->sparm.b4.a_current_ess_id);
+                                             memtmp);
                                } else {
                                        dev_dbg(&link->dev,
                                              "ray_cs interrupt network \"%s\" joined\n",
-                                             local->sparm.b4.a_current_ess_id);
+                                             memtmp);
                                }
                                memcpy_fromio(&local->bss_id,
                                              pccs->var.start_network.bssid,
@@ -1939,12 +1948,12 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
                                if (status == CCS_START_NETWORK) {
                                        dev_dbg(&link->dev,
                                              "ray_cs interrupt network \"%s\" start failed\n",
-                                             local->sparm.b4.a_current_ess_id);
+                                             memtmp);
                                        local->timer.function = start_net;
                                } else {
                                        dev_dbg(&link->dev,
                                              "ray_cs interrupt network \"%s\" join failed\n",
-                                             local->sparm.b4.a_current_ess_id);
+                                             memtmp);
                                        local->timer.function = join_net;
                                }
                                add_timer(&local->timer);
index 197b4466a5d2a44378f998fdefa2c221ae6124c6..a5c694f23d334ff1308d1797ee1b697baa82caab 100644 (file)
@@ -1296,8 +1296,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_CONTROL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
                           !(filter_flags & FIF_PSPOLL));
-       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA,
-                          !(filter_flags & FIF_CONTROL));
+       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 0);
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
                           !(filter_flags & FIF_CONTROL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
@@ -3866,6 +3865,400 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
        return rfcsr24;
 }
 
+static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
+       rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
+       rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
+       rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
+       rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
+       rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
+       rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+       rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
+       rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
+       rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
+       rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
+       rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
+       rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+       rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
+       rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
+       rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+}
+
+static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
+       rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
+       rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+       rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
+       rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
+       rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
+       rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
+       rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+       rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
+}
+
+static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+       rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
+       rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+       rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
+       rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
+       rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+       rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
+       rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+       rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+       rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+       rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+       rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+       rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+       rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
+       rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+       rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+       rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+       rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
+       rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+       rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+       rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+       rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+       rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
+       rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+       rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
+}
+
+static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
+       rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
+       rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
+       rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
+       rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
+       rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
+       rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
+       rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
+       rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
+       rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
+       rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
+       rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
+       rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
+       rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
+       rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
+       rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
+       rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
+       rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
+       rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
+       rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
+       rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
+       rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
+       rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
+       rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
+       rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
+       rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
+       rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
+       rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
+       rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+}
+
+static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
+       rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
+       rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
+       rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
+       rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
+       rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
+       rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+       rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+       rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
+       rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
+       rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
+       rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
+       rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
+       rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
+       rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+       rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+}
+
+static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
+       rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
+       rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
+       rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
+       rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
+       rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
+       rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+       rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
+       rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
+       rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
+       rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
+       rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
+       rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
+       rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+       rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
+}
+
+static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+       rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+               rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+       else
+               rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+       rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+       rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
+
+       rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+       rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+               rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+       else
+               rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
+       rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+       rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+       rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+       rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+       rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+       rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+               rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+       else
+               rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
+       rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+       rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
+       rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
+       rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+       rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+               rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+       else
+               rt2800_rfcsr_write(rt2x00dev, 46, 0x7b);
+       rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+
+       rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+               rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+       else
+               rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
+       rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+       rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
+       rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
+       rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+       rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
+
+       rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+               rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
+       else
+               rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
+       rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+}
+
+static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
+       rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+       rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+       rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
+       rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+       rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
+       rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+       rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+       rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
+       rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
+       rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+       rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+       rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+       rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
+       rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+       rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
+       rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+       rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+       rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
+       rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+       rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+       rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+       rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
+       rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+       rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
+       rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
+       rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
+       rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
+       rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
+       rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+       rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
+       rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
+       rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
+       rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+       rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
+       rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
+       rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
+}
+
 static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 {
        struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
@@ -3889,6 +4282,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        /*
         * Init RF calibration.
         */
+
        if (rt2x00_rt(rt2x00dev, RT3290) ||
            rt2x00_rt(rt2x00dev, RT5390) ||
            rt2x00_rt(rt2x00dev, RT5392)) {
@@ -3907,379 +4301,35 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
        }
 
-       if (rt2x00_rt(rt2x00dev, RT3070) ||
-           rt2x00_rt(rt2x00dev, RT3071) ||
-           rt2x00_rt(rt2x00dev, RT3090)) {
-               rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
-               rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
-               rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
-               rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
-               rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
-       } else if (rt2x00_rt(rt2x00dev, RT3290)) {
-               rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
-               rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
-               rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
-               rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
-               rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-               rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
-               rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-               rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
-               rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-               rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
-               rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
-               rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-               rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-               rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-               rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
-               rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
-               rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
-               rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
-               rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
-               rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
-               rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-               rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
-       } else if (rt2x00_rt(rt2x00dev, RT3390)) {
-               rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
-               rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
-               rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
-               rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
-               rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
-               rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
-               rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
-               rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
-               rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
-               rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
-               rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
-       } else if (rt2x00_rt(rt2x00dev, RT3572)) {
-               rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
-               rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
-               rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
-               rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
-               rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
-               rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
-               rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
-               rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
-               rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
-               rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
-       } else if (rt2800_is_305x_soc(rt2x00dev)) {
-               rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
-               rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
-               rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
-               rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
-               rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
-               rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
-               rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
-               rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
-               rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
-               rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
-               rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+       if (rt2800_is_305x_soc(rt2x00dev)) {
+               rt2800_init_rfcsr_305x_soc(rt2x00dev);
                return 0;
-       } else if (rt2x00_rt(rt2x00dev, RT3352)) {
-               rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
-               rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
-               rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
-               rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
-               rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
-               rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
-               rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
-               rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
-               rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
-               rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
-               rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
-               rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
-               rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
-               rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
-               rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
-               rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
-               rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
-               rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
-               rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
-               rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
-               rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
-               rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
-               rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
-               rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
-       } else if (rt2x00_rt(rt2x00dev, RT5390)) {
-               rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
-               if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-                       rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
-               else
-                       rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-               rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
-
-               rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-               rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-               if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-                       rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-               else
-                       rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-               rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-
-               rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
-               rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-               rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
-               rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
-               rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-
-               if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-                       rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
-               else
-                       rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
-               rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-               rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
-               rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
-               rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-               rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-               if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-                       rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-               else
-                       rt2800_rfcsr_write(rt2x00dev, 46, 0x7b);
-               rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
-
-               rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
-               if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-                       rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
-               else
-                       rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
-               rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
-               rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
-               rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
-               rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
-               rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
-
-               rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-               if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-                       rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
-               else
-                       rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
-               rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
-       } else if (rt2x00_rt(rt2x00dev, RT5392)) {
-               rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-               rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-               rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
-               rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
-               rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-               rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
-               rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-               rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-               rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
-               rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
-               rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
-               rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-               rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
-               rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
-               rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-               rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-               rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
-               rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
-               rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-               rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-               rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-               rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
-               rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-               rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
-               rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
-               rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
-               rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
-               rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
-               rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
-               rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
-               rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
-               rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
-               rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
-               rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-               rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
-               rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
-               rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
+       }
+
+       switch (rt2x00dev->chip.rt) {
+       case RT3070:
+       case RT3071:
+       case RT3090:
+               rt2800_init_rfcsr_30xx(rt2x00dev);
+               break;
+       case RT3290:
+               rt2800_init_rfcsr_3290(rt2x00dev);
+               break;
+       case RT3352:
+               rt2800_init_rfcsr_3352(rt2x00dev);
+               break;
+       case RT3390:
+               rt2800_init_rfcsr_3390(rt2x00dev);
+               break;
+       case RT3572:
+               rt2800_init_rfcsr_3572(rt2x00dev);
+               break;
+       case RT5390:
+               rt2800_init_rfcsr_5390(rt2x00dev);
+               break;
+       case RT5392:
+               rt2800_init_rfcsr_5392(rt2x00dev);
+               break;
        }
 
        if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
@@ -4620,12 +4670,14 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
        mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 {
        unsigned int i;
 
        for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
                rt2800_efuse_read(rt2x00dev, i);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
 
@@ -4635,11 +4687,14 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
        u16 word;
        u8 *mac;
        u8 default_lna_gain;
+       int retval;
 
        /*
         * Read the EEPROM.
         */
-       rt2800_read_eeprom(rt2x00dev);
+       retval = rt2800_read_eeprom(rt2x00dev);
+       if (retval)
+               return retval;
 
        /*
         * Start validation of the data that has been read.
@@ -5090,8 +5145,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
            IEEE80211_HW_SUPPORTS_PS |
            IEEE80211_HW_PS_NULLFUNC_STACK |
            IEEE80211_HW_AMPDU_AGGREGATION |
-           IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-           IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL;
+           IEEE80211_HW_REPORTS_TX_ACK_STATUS;
 
        /*
         * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
@@ -5484,7 +5538,9 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        case IEEE80211_AMPDU_TX_START:
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
index a128ceadcb3e733620c37fa03e49666cf80b2e09..6ec739466db46e681f86fc4f59a282949082cf38 100644 (file)
@@ -43,7 +43,7 @@ struct rt2800_ops {
                            const unsigned int offset,
                            const struct rt2x00_field32 field, u32 *reg);
 
-       void (*read_eeprom)(struct rt2x00_dev *rt2x00dev);
+       int (*read_eeprom)(struct rt2x00_dev *rt2x00dev);
        bool (*hwcrypt_disabled)(struct rt2x00_dev *rt2x00dev);
 
        int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
@@ -117,11 +117,11 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev,
        return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
 }
 
-static inline void rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev)
 {
        const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
-       rt2800ops->read_eeprom(rt2x00dev);
+       return rt2800ops->read_eeprom(rt2x00dev);
 }
 
 static inline bool rt2800_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
@@ -207,7 +207,7 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
 void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
+int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
 
index 9224d874bf24b62e017bfe8906f686b929a45db6..0e8d1705e3687f28e81a0bfd765dcdbe55afef73 100644 (file)
@@ -90,17 +90,22 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
 }
 
 #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
-static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
        void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
 
+       if (!base_addr)
+               return -ENOMEM;
+
        memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
 
        iounmap(base_addr);
+       return 0;
 }
 #else
-static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
+       return -ENOMEM;
 }
 #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
 
@@ -135,7 +140,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
        rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
 }
 
-static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
 {
        struct eeprom_93cx6 eeprom;
        u32 reg;
@@ -164,6 +169,8 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
 
        eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
                               EEPROM_SIZE / sizeof(u16));
+
+       return 0;
 }
 
 static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
@@ -171,13 +178,14 @@ static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
        return rt2800_efuse_detect(rt2x00dev);
 }
 
-static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 {
-       rt2800_read_eeprom_efuse(rt2x00dev);
+       return rt2800_read_eeprom_efuse(rt2x00dev);
 }
 #else
-static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
 {
+       return -EOPNOTSUPP;
 }
 
 static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
@@ -185,8 +193,9 @@ static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
        return 0;
 }
 
-static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 {
+       return -EOPNOTSUPP;
 }
 #endif /* CONFIG_PCI */
 
@@ -970,14 +979,18 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
 /*
  * Device probe functions.
  */
-static void rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
 {
+       int retval;
+
        if (rt2x00_is_soc(rt2x00dev))
-               rt2800pci_read_eeprom_soc(rt2x00dev);
+               retval = rt2800pci_read_eeprom_soc(rt2x00dev);
        else if (rt2800pci_efuse_detect(rt2x00dev))
-               rt2800pci_read_eeprom_efuse(rt2x00dev);
+               retval = rt2800pci_read_eeprom_efuse(rt2x00dev);
        else
-               rt2800pci_read_eeprom_pci(rt2x00dev);
+               retval = rt2800pci_read_eeprom_pci(rt2x00dev);
+
+       return retval;
 }
 
 static const struct ieee80211_ops rt2800pci_mac80211_ops = {
index 5c149b58ab46dd61b53406511352b3f80f7c48cb..4721cada159105c443791882dfe4344bf4b8d3c0 100644 (file)
@@ -735,13 +735,17 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
 /*
  * Device probe functions.
  */
-static void rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
 {
+       int retval;
+
        if (rt2800_efuse_detect(rt2x00dev))
-               rt2800_read_eeprom_efuse(rt2x00dev);
+               retval = rt2800_read_eeprom_efuse(rt2x00dev);
        else
-               rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
-                                     EEPROM_SIZE);
+               retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
+                                              EEPROM_SIZE);
+
+       return retval;
 }
 
 static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
index 0751b35ef6dcd536ba51c3554dc4b58e359a9628..b52512b8ac5fd0632ce2c6fcf7aa34dd373e3acc 100644 (file)
@@ -1016,6 +1016,26 @@ struct rt2x00_dev {
         * Protect the interrupt mask register.
         */
        spinlock_t irqmask_lock;
+
+       /*
+        * List of BlockAckReq TX entries that need driver BlockAck processing.
+        */
+       struct list_head bar_list;
+       spinlock_t bar_list_lock;
+};
+
+struct rt2x00_bar_list_entry {
+       struct list_head list;
+       struct rcu_head head;
+
+       struct queue_entry *entry;
+       int block_acked;
+
+       /* Relevant parts of the IEEE80211 BAR header */
+       __u8 ra[6];
+       __u8 ta[6];
+       __le16 control;
+       __le16 start_seq_num;
 };
 
 /*
index 44f8b3f3cbede976cb97ab132f032a1d136549e1..b40a53857498b48576beae6ccb4a83a03ded2360 100644 (file)
@@ -271,6 +271,50 @@ void rt2x00lib_dmadone(struct queue_entry *entry)
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
 
+static inline int rt2x00lib_txdone_bar_status(struct queue_entry *entry)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct ieee80211_bar *bar = (void *) entry->skb->data;
+       struct rt2x00_bar_list_entry *bar_entry;
+       int ret;
+
+       if (likely(!ieee80211_is_back_req(bar->frame_control)))
+               return 0;
+
+       /*
+        * Unlike all other frames, the status report for BARs does
+        * not directly come from the hardware as it is incapable of
+        * matching a BA to a previously send BAR. The hardware will
+        * report all BARs as if they weren't acked at all.
+        *
+        * Instead the RX-path will scan for incoming BAs and set the
+        * block_acked flag if it sees one that was likely caused by
+        * a BAR from us.
+        *
+        * Remove remaining BARs here and return their status for
+        * TX done processing.
+        */
+       ret = 0;
+       rcu_read_lock();
+       list_for_each_entry_rcu(bar_entry, &rt2x00dev->bar_list, list) {
+               if (bar_entry->entry != entry)
+                       continue;
+
+               spin_lock_bh(&rt2x00dev->bar_list_lock);
+               /* Return whether this BAR was blockacked or not */
+               ret = bar_entry->block_acked;
+               /* Remove the BAR from our checklist */
+               list_del_rcu(&bar_entry->list);
+               spin_unlock_bh(&rt2x00dev->bar_list_lock);
+               kfree_rcu(bar_entry, head);
+
+               break;
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc)
 {
@@ -324,9 +368,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
 
        /*
-        * Determine if the frame has been successfully transmitted.
+        * Determine if the frame has been successfully transmitted and
+        * remove BARs from our check list while checking for their
+        * TX status.
         */
        success =
+           rt2x00lib_txdone_bar_status(entry) ||
            test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
            test_bit(TXDONE_UNKNOWN, &txdesc->flags);
 
@@ -491,6 +538,50 @@ static void rt2x00lib_sleep(struct work_struct *work)
                                 IEEE80211_CONF_CHANGE_PS);
 }
 
+static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev,
+                                     struct sk_buff *skb,
+                                     struct rxdone_entry_desc *rxdesc)
+{
+       struct rt2x00_bar_list_entry *entry;
+       struct ieee80211_bar *ba = (void *)skb->data;
+
+       if (likely(!ieee80211_is_back(ba->frame_control)))
+               return;
+
+       if (rxdesc->size < sizeof(*ba) + FCS_LEN)
+               return;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(entry, &rt2x00dev->bar_list, list) {
+
+               if (ba->start_seq_num != entry->start_seq_num)
+                       continue;
+
+#define TID_CHECK(a, b) (                                              \
+       ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) ==        \
+       ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)))          \
+
+               if (!TID_CHECK(ba->control, entry->control))
+                       continue;
+
+#undef TID_CHECK
+
+               if (compare_ether_addr(ba->ra, entry->ta))
+                       continue;
+
+               if (compare_ether_addr(ba->ta, entry->ra))
+                       continue;
+
+               /* Mark BAR since we received the according BA */
+               spin_lock_bh(&rt2x00dev->bar_list_lock);
+               entry->block_acked = 1;
+               spin_unlock_bh(&rt2x00dev->bar_list_lock);
+               break;
+       }
+       rcu_read_unlock();
+
+}
+
 static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
                                      struct sk_buff *skb,
                                      struct rxdone_entry_desc *rxdesc)
@@ -673,6 +764,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
         */
        rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc);
 
+       /*
+        * Check for incoming BlockAcks to match to the BlockAckReqs
+        * we've send out.
+        */
+       rt2x00lib_rxdone_check_ba(rt2x00dev, entry->skb, &rxdesc);
+
        /*
         * Update extra components
         */
@@ -1183,6 +1280,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 
        spin_lock_init(&rt2x00dev->irqmask_lock);
        mutex_init(&rt2x00dev->csr_mutex);
+       INIT_LIST_HEAD(&rt2x00dev->bar_list);
+       spin_lock_init(&rt2x00dev->bar_list_lock);
 
        set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
 
index e488b944a0340834ed96c02c91df59e9b3f5e142..f35d85a71bbcab0e416f4e6db115e82538098414 100644 (file)
@@ -582,6 +582,48 @@ static void rt2x00queue_kick_tx_queue(struct data_queue *queue,
                queue->rt2x00dev->ops->lib->kick_queue(queue);
 }
 
+static void rt2x00queue_bar_check(struct queue_entry *entry)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct ieee80211_bar *bar = (void *) (entry->skb->data +
+                                   rt2x00dev->ops->extra_tx_headroom);
+       struct rt2x00_bar_list_entry *bar_entry;
+
+       if (likely(!ieee80211_is_back_req(bar->frame_control)))
+               return;
+
+       bar_entry = kmalloc(sizeof(*bar_entry), GFP_ATOMIC);
+
+       /*
+        * If the alloc fails we still send the BAR out but just don't track
+        * it in our bar list. And as a result we will report it to mac80211
+        * back as failed.
+        */
+       if (!bar_entry)
+               return;
+
+       bar_entry->entry = entry;
+       bar_entry->block_acked = 0;
+
+       /*
+        * Copy the relevant parts of the 802.11 BAR into out check list
+        * such that we can use RCU for less-overhead in the RX path since
+        * sending BARs and processing the according BlockAck should be
+        * the exception.
+        */
+       memcpy(bar_entry->ra, bar->ra, sizeof(bar->ra));
+       memcpy(bar_entry->ta, bar->ta, sizeof(bar->ta));
+       bar_entry->control = bar->control;
+       bar_entry->start_seq_num = bar->start_seq_num;
+
+       /*
+        * Insert BAR into our BAR check list.
+        */
+       spin_lock_bh(&rt2x00dev->bar_list_lock);
+       list_add_tail_rcu(&bar_entry->list, &rt2x00dev->bar_list);
+       spin_unlock_bh(&rt2x00dev->bar_list_lock);
+}
+
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
                               bool local)
 {
@@ -680,6 +722,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
                goto out;
        }
 
+       /*
+        * Put BlockAckReqs into our check list for driver BA processing.
+        */
+       rt2x00queue_bar_check(entry);
+
        set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
        rt2x00queue_index_inc(entry, Q_INDEX);
index be33aa14c8afaa6672497d156abebb4b3cd146f9..d3ce9fbef00ee0b8d3e88eefcfd7111d9d0080ae 100644 (file)
@@ -879,7 +879,9 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
                         "IEEE80211_AMPDU_TX_START: TID:%d\n", tid);
                return rtl_tx_agg_start(hw, sta, tid, ssn);
                break;
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
                RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
                         "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
                return rtl_tx_agg_stop(hw, sta, tid);
index c1608cddc5299e5150a323d0a3efb7a2f0b63de6..d7d0d4948b01f2e804e6bcddfca93b10c7cdb312 100644 (file)
@@ -158,8 +158,6 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
        const struct ieee80211_reg_rule *reg_rule;
        struct ieee80211_channel *ch;
        unsigned int i;
-       u32 bandwidth = 0;
-       int r;
 
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 
@@ -174,9 +172,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
                            (ch->flags & IEEE80211_CHAN_RADAR))
                                continue;
                        if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                               r = freq_reg_info(wiphy, ch->center_freq,
-                                                 bandwidth, &reg_rule);
-                               if (r)
+                               reg_rule = freq_reg_info(wiphy, ch->center_freq);
+                               if (IS_ERR(reg_rule))
                                        continue;
 
                                /*
@@ -211,8 +208,6 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *ch;
        const struct ieee80211_reg_rule *reg_rule;
-       u32 bandwidth = 0;
-       int r;
 
        if (!wiphy->bands[IEEE80211_BAND_2GHZ])
                return;
@@ -240,16 +235,16 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
         */
 
        ch = &sband->channels[11];      /* CH 12 */
-       r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-       if (!r) {
+       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       if (!IS_ERR(reg_rule)) {
                if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
                        if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
                                ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
        }
 
        ch = &sband->channels[12];      /* CH 13 */
-       r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-       if (!r) {
+       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       if (!IS_ERR(reg_rule)) {
                if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
                        if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
                                ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -303,9 +298,9 @@ static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
        return;
 }
 
-static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
-                                  struct regulatory_request *request,
-                                  struct rtl_regulatory *reg)
+static void _rtl_reg_notifier_apply(struct wiphy *wiphy,
+                                   struct regulatory_request *request,
+                                   struct rtl_regulatory *reg)
 {
        /* We always apply this */
        _rtl_reg_apply_radar_flags(wiphy);
@@ -319,8 +314,6 @@ static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
                _rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
                break;
        }
-
-       return 0;
 }
 
 static const struct ieee80211_regdomain *_rtl_regdomain_select(
@@ -353,9 +346,9 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
 
 static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
                                struct wiphy *wiphy,
-                               int (*reg_notifier) (struct wiphy *wiphy,
-                                                    struct regulatory_request *
-                                                    request))
+                               void (*reg_notifier) (struct wiphy *wiphy,
+                                                     struct regulatory_request *
+                                                     request))
 {
        const struct ieee80211_regdomain *regd;
 
@@ -384,7 +377,7 @@ static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
 }
 
 int rtl_regd_init(struct ieee80211_hw *hw,
-                 int (*reg_notifier) (struct wiphy *wiphy,
+                 void (*reg_notifier) (struct wiphy *wiphy,
                                       struct regulatory_request *request))
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -426,12 +419,12 @@ int rtl_regd_init(struct ieee80211_hw *hw,
        return 0;
 }
 
-int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
        RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, "\n");
 
-       return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
+       _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
 }
index 70ef2f418a44134d1fd1d810afd5f4ace4705151..4e1f4f00e6e9633ed30c59ca2220039e733fdb39 100644 (file)
@@ -55,7 +55,7 @@ enum country_code_type_t {
 };
 
 int rtl_regd_init(struct ieee80211_hw *hw,
-                 int (*reg_notifier) (struct wiphy *wiphy,
-                                      struct regulatory_request *request));
-int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+                 void (*reg_notifier) (struct wiphy *wiphy,
+                                       struct regulatory_request *request));
+void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
 #endif
index a0fbf284420ec78b2570756dc4c1edd2638be057..cdb570ffb4b5028a6243e8d7fe6c5f76da617478 100644 (file)
@@ -452,7 +452,7 @@ static void _rtl92de_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        u8 *praddr;
        u16 type, cfc;
        __le16 fc;
-       bool packet_matchbssid, packet_toself, packet_beacon;
+       bool packet_matchbssid, packet_toself, packet_beacon = false;
 
        tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
        hdr = (struct ieee80211_hdr *)tmp_buf;
index 206561d7282f906a6662ce43610f87666362dbe3..f8431a3c2c9d6ba1380b358d26ac0743bb9ef9cb 100644 (file)
@@ -480,7 +480,7 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        u8 *praddr;
        __le16 fc;
        u16 type, cfc;
-       bool packet_matchbssid, packet_toself, packet_beacon;
+       bool packet_matchbssid, packet_toself, packet_beacon = false;
 
        tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 
index a313be8c21d28d5708fdbc34e49f0db3fa7836a2..ce8ad12bce5b1099970937af0a77cb2ec031d4f1 100644 (file)
@@ -247,7 +247,7 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        u8 *psaddr;
        __le16 fc;
        u16 type;
-       bool packet_matchbssid, packet_toself, packet_beacon;
+       bool packet_matchbssid, packet_toself, packet_beacon = false;
 
        tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
 
index ea9d8e011bc9d45f5414b43cb6d1e3af492a89c3..ce6e62a37e1433341d3bb2c9a5ccb2c6d2cde7d4 100644 (file)
@@ -89,8 +89,8 @@ static int wl12xx_set_authorized(struct wl1271 *wl,
        return 0;
 }
 
-static int wl1271_reg_notify(struct wiphy *wiphy,
-                            struct regulatory_request *request)
+static void wl1271_reg_notify(struct wiphy *wiphy,
+                             struct regulatory_request *request)
 {
        struct ieee80211_supported_band *band;
        struct ieee80211_channel *ch;
@@ -107,8 +107,6 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
                                     IEEE80211_CHAN_PASSIVE_SCAN;
 
        }
-
-       return 0;
 }
 
 static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -4575,7 +4573,9 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
         * Falling break here on purpose for all TX APDU commands.
         */
        case IEEE80211_AMPDU_TX_START:
-       case IEEE80211_AMPDU_TX_STOP:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
        case IEEE80211_AMPDU_TX_OPERATIONAL:
                ret = -EINVAL;
                break;
index 6678d4b18611556be7617b6ff79dab0dad851d14..5ce26cf402fcf2b68ebc998dec1aaba258a9d949 100644 (file)
@@ -122,9 +122,9 @@ enum {
 
 struct wl1271_chip {
        u32 id;
-       char fw_ver_str[ETHTOOL_BUSINFO_LEN];
+       char fw_ver_str[ETHTOOL_FWVERS_LEN];
        unsigned int fw_ver[NUM_FW_VER];
-       char phy_fw_ver_str[ETHTOOL_BUSINFO_LEN];
+       char phy_fw_ver_str[ETHTOOL_FWVERS_LEN];
 };
 
 #define NUM_TX_QUEUES              4
index b7d41f8c338a8372cea8bfe6649386c6a0d8b090..f733cae3d4b643618cec69f4aeadd84044eff7bd 100644 (file)
@@ -238,6 +238,8 @@ static const struct net_device_ops xenvif_netdev_ops = {
        .ndo_stop       = xenvif_close,
        .ndo_change_mtu = xenvif_change_mtu,
        .ndo_fix_features = xenvif_fix_features,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr   = eth_validate_addr,
 };
 
 struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
index ec857676c39ffaffcb6d55c25917ec9beb1192ea..80c728b28828dc538ca19d5e3ef9f756ee968568 100644 (file)
@@ -5,19 +5,6 @@
 menu "Near Field Communication (NFC) devices"
        depends on NFC
 
-config PN544_HCI_NFC
-       tristate "HCI PN544 NFC driver"
-       depends on I2C && NFC_HCI && NFC_SHDLC
-       select CRC_CCITT
-       default n
-       ---help---
-         NXP PN544 i2c driver.
-         This is a driver based on the SHDLC and HCI NFC kernel layers and
-         will thus not work with NXP libnfc library.
-
-         To compile this driver as a module, choose m here. The module will
-         be called pn544_hci.
-
 config NFC_PN533
        tristate "NXP PN533 USB driver"
        depends on USB
@@ -39,4 +26,6 @@ config NFC_WILINK
          Say Y here to compile support for Texas Instrument's NFC WiLink driver
          into the kernel or say M to compile it as module.
 
+source "drivers/nfc/pn544/Kconfig"
+
 endmenu
index 36c359043f5469b8d59b4235d9cea35db79d779e..574bbc04d97a46154d1a6e2874f6d3f803f5081f 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for nfc devices
 #
 
-obj-$(CONFIG_PN544_HCI_NFC)    += pn544/
+obj-$(CONFIG_NFC_PN544)                += pn544/
 obj-$(CONFIG_NFC_PN533)                += pn533.o
 obj-$(CONFIG_NFC_WILINK)       += nfcwilink.o
 
index 50b1ee41afc60e2a3789f1a4e26ab12ff811ce4e..3b731acbc408fbc807ea8ffa4eef9f0dc622e97f 100644 (file)
@@ -526,7 +526,7 @@ static int nfcwilink_probe(struct platform_device *pdev)
 
        nfc_dev_dbg(&pdev->dev, "probe entry");
 
-       drv = kzalloc(sizeof(struct nfcwilink), GFP_KERNEL);
+       drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
        if (!drv) {
                rc = -ENOMEM;
                goto exit;
@@ -542,12 +542,13 @@ static int nfcwilink_probe(struct platform_device *pdev)
 
        drv->ndev = nci_allocate_device(&nfcwilink_ops,
                                        protocols,
+                                       NFC_SE_NONE,
                                        NFCWILINK_HDR_LEN,
                                        0);
        if (!drv->ndev) {
                nfc_dev_err(&pdev->dev, "nci_allocate_device failed");
                rc = -ENOMEM;
-               goto free_exit;
+               goto exit;
        }
 
        nci_set_parent_dev(drv->ndev, &pdev->dev);
@@ -566,9 +567,6 @@ static int nfcwilink_probe(struct platform_device *pdev)
 free_dev_exit:
        nci_free_device(drv->ndev);
 
-free_exit:
-       kfree(drv);
-
 exit:
        return rc;
 }
@@ -588,8 +586,6 @@ static int nfcwilink_remove(struct platform_device *pdev)
        nci_unregister_device(ndev);
        nci_free_device(ndev);
 
-       kfree(drv);
-
        dev_set_drvdata(&pdev->dev, NULL);
 
        return 0;
index ada681b01a17be24ecfa93b8c0ddf518c32c5c1c..f696318cfb512eb80c70623ee4e9d23edf27abbf 100644 (file)
 #define SONY_VENDOR_ID         0x054c
 #define PASORI_PRODUCT_ID      0x02e1
 
-#define PN533_QUIRKS_TYPE_A          BIT(0)
-#define PN533_QUIRKS_TYPE_F          BIT(1)
-#define PN533_QUIRKS_DEP             BIT(2)
-#define PN533_QUIRKS_RAW_EXCHANGE    BIT(3)
-
 #define PN533_DEVICE_STD    0x1
 #define PN533_DEVICE_PASORI 0x2
 
@@ -84,14 +79,18 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_LISTEN_TIME 2
 
 /* frame definitions */
-#define PN533_NORMAL_FRAME_MAX_LEN 262  /* 6   (PREAMBLE, SOF, LEN, LCS, TFI)
-                                          254 (DATA)
-                                          2   (DCS, postamble) */
-
-#define PN533_FRAME_TAIL_SIZE 2
-#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
-                               PN533_FRAME_TAIL_SIZE)
-#define PN533_FRAME_ACK_SIZE (sizeof(struct pn533_frame) + 1)
+#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \
+                                       + 2) /* data[0] TFI, data[1] CC */
+#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
+
+/*
+ * Max extended frame payload len, excluding TFI and CC
+ * which are already in PN533_FRAME_HEADER_LEN.
+ */
+#define PN533_FRAME_MAX_PAYLOAD_LEN 263
+
+#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
+                                 Postamble (1) */
 #define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
 #define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
 
@@ -105,8 +104,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 
 /* PN533 Commands */
 #define PN533_FRAME_CMD(f) (f->data[1])
-#define PN533_FRAME_CMD_PARAMS_PTR(f) (&f->data[2])
-#define PN533_FRAME_CMD_PARAMS_LEN(f) (f->datalen - 2)
 
 #define PN533_CMD_GET_FIRMWARE_VERSION 0x02
 #define PN533_CMD_RF_CONFIGURATION 0x32
@@ -120,6 +117,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_CMD_TG_INIT_AS_TARGET 0x8c
 #define PN533_CMD_TG_GET_DATA 0x86
 #define PN533_CMD_TG_SET_DATA 0x8e
+#define PN533_CMD_UNDEF 0xff
 
 #define PN533_CMD_RESPONSE(cmd) (cmd + 1)
 
@@ -128,13 +126,12 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_CMD_MI_MASK 0x40
 #define PN533_CMD_RET_SUCCESS 0x00
 
-/* PN533 status codes */
-#define PN533_STATUS_TARGET_RELEASED 0x29
-
 struct pn533;
 
-typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
-                                       u8 *params, int params_len);
+typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status);
+
+typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg,
+                                       struct sk_buff *resp);
 
 /* structs for pn533 commands */
 
@@ -282,11 +279,6 @@ const struct pn533_poll_modulations poll_mod[] = {
 
 /* PN533_CMD_IN_ATR */
 
-struct pn533_cmd_activate_param {
-       u8 tg;
-       u8 next;
-} __packed;
-
 struct pn533_cmd_activate_response {
        u8 status;
        u8 nfcid3t[10];
@@ -299,14 +291,6 @@ struct pn533_cmd_activate_response {
        u8 gt[];
 } __packed;
 
-/* PN533_CMD_IN_JUMP_FOR_DEP */
-struct pn533_cmd_jump_dep {
-       u8 active;
-       u8 baud;
-       u8 next;
-       u8 data[];
-} __packed;
-
 struct pn533_cmd_jump_dep_response {
        u8 status;
        u8 tg;
@@ -329,32 +313,13 @@ struct pn533_cmd_jump_dep_response {
 #define PN533_INIT_TARGET_RESP_ACTIVE     0x1
 #define PN533_INIT_TARGET_RESP_DEP        0x4
 
-struct pn533_cmd_init_target {
-       u8 mode;
-       u8 mifare[6];
-       u8 felica[18];
-       u8 nfcid3[10];
-       u8 gb_len;
-       u8 gb[];
-} __packed;
-
-struct pn533_cmd_init_target_response {
-       u8 mode;
-       u8 cmd[];
-} __packed;
-
 struct pn533 {
        struct usb_device *udev;
        struct usb_interface *interface;
        struct nfc_dev *nfc_dev;
 
        struct urb *out_urb;
-       int out_maxlen;
-       struct pn533_frame *out_frame;
-
        struct urb *in_urb;
-       int in_maxlen;
-       struct pn533_frame *in_frame;
 
        struct sk_buff_head resp_q;
 
@@ -365,12 +330,12 @@ struct pn533 {
        struct work_struct mi_work;
        struct work_struct tg_work;
        struct timer_list listen_timer;
-       struct pn533_frame *wq_in_frame;
        int wq_in_error;
        int cancel_listen;
 
        pn533_cmd_complete_t cmd_complete;
        void *cmd_complete_arg;
+       void *cmd_complete_mi_arg;
        struct mutex cmd_lock;
        u8 cmd;
 
@@ -391,16 +356,17 @@ struct pn533 {
 
        struct list_head cmd_queue;
        u8 cmd_pending;
+
+       struct pn533_frame_ops *ops;
 };
 
 struct pn533_cmd {
        struct list_head queue;
-       struct pn533_frame *out_frame;
-       struct pn533_frame *in_frame;
-       int in_frame_len;
-       pn533_cmd_complete_t cmd_complete;
+       u8 cmd_code;
+       struct sk_buff *req;
+       struct sk_buff *resp;
+       int resp_len;
        void *arg;
-       gfp_t flags;
 };
 
 struct pn533_frame {
@@ -411,6 +377,22 @@ struct pn533_frame {
        u8 data[];
 } __packed;
 
+struct pn533_frame_ops {
+       void (*tx_frame_init)(void *frame, u8 cmd_code);
+       void (*tx_frame_finish)(void *frame);
+       void (*tx_update_payload_len)(void *frame, int len);
+       int tx_header_len;
+       int tx_tail_len;
+
+       bool (*rx_is_frame_valid)(void *frame);
+       int (*rx_frame_size)(void *frame);
+       int rx_header_len;
+       int rx_tail_len;
+
+       int max_payload_len;
+       u8 (*get_cmd_code)(void *frame);
+};
+
 /* The rule: value + checksum = 0 */
 static inline u8 pn533_checksum(u8 value)
 {
@@ -429,37 +411,21 @@ static u8 pn533_data_checksum(u8 *data, int datalen)
        return pn533_checksum(sum);
 }
 
-/**
- * pn533_tx_frame_ack - create a ack frame
- * @frame:     The frame to be set as ack
- *
- * Ack is different type of standard frame. As a standard frame, it has
- * preamble and start_frame. However the checksum of this frame must fail,
- * i.e. datalen + datalen_checksum must NOT be zero. When the checksum test
- * fails and datalen = 0 and datalen_checksum = 0xFF, the frame is a ack.
- * After datalen_checksum field, the postamble is placed.
- */
-static void pn533_tx_frame_ack(struct pn533_frame *frame)
+static void pn533_tx_frame_init(void *_frame, u8 cmd_code)
 {
-       frame->preamble = 0;
-       frame->start_frame = cpu_to_be16(PN533_SOF);
-       frame->datalen = 0;
-       frame->datalen_checksum = 0xFF;
-       /* data[0] is used as postamble */
-       frame->data[0] = 0;
-}
+       struct pn533_frame *frame = _frame;
 
-static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd)
-{
        frame->preamble = 0;
        frame->start_frame = cpu_to_be16(PN533_SOF);
        PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
-       PN533_FRAME_CMD(frame) = cmd;
+       PN533_FRAME_CMD(frame) = cmd_code;
        frame->datalen = 2;
 }
 
-static void pn533_tx_frame_finish(struct pn533_frame *frame)
+static void pn533_tx_frame_finish(void *_frame)
 {
+       struct pn533_frame *frame = _frame;
+
        frame->datalen_checksum = pn533_checksum(frame->datalen);
 
        PN533_FRAME_CHECKSUM(frame) =
@@ -468,9 +434,17 @@ static void pn533_tx_frame_finish(struct pn533_frame *frame)
        PN533_FRAME_POSTAMBLE(frame) = 0;
 }
 
-static bool pn533_rx_frame_is_valid(struct pn533_frame *frame)
+static void pn533_tx_update_payload_len(void *_frame, int len)
+{
+       struct pn533_frame *frame = _frame;
+
+       frame->datalen += len;
+}
+
+static bool pn533_rx_frame_is_valid(void *_frame)
 {
        u8 checksum;
+       struct pn533_frame *frame = _frame;
 
        if (frame->start_frame != cpu_to_be16(PN533_SOF))
                return false;
@@ -497,28 +471,48 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
        return true;
 }
 
-static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)
+static inline int pn533_rx_frame_size(void *frame)
+{
+       struct pn533_frame *f = frame;
+
+       return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN;
+}
+
+static u8 pn533_get_cmd_code(void *frame)
+{
+       struct pn533_frame *f = frame;
+
+       return PN533_FRAME_CMD(f);
+}
+
+struct pn533_frame_ops pn533_std_frame_ops = {
+       .tx_frame_init = pn533_tx_frame_init,
+       .tx_frame_finish = pn533_tx_frame_finish,
+       .tx_update_payload_len = pn533_tx_update_payload_len,
+       .tx_header_len = PN533_FRAME_HEADER_LEN,
+       .tx_tail_len = PN533_FRAME_TAIL_LEN,
+
+       .rx_is_frame_valid = pn533_rx_frame_is_valid,
+       .rx_frame_size = pn533_rx_frame_size,
+       .rx_header_len = PN533_FRAME_HEADER_LEN,
+       .rx_tail_len = PN533_FRAME_TAIL_LEN,
+
+       .max_payload_len =  PN533_FRAME_MAX_PAYLOAD_LEN,
+       .get_cmd_code = pn533_get_cmd_code,
+};
+
+static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame)
 {
-       return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd));
+       return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd));
 }
 
 
 static void pn533_wq_cmd_complete(struct work_struct *work)
 {
        struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
-       struct pn533_frame *in_frame;
        int rc;
 
-       in_frame = dev->wq_in_frame;
-
-       if (dev->wq_in_error)
-               rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL,
-                                                       dev->wq_in_error);
-       else
-               rc = dev->cmd_complete(dev, dev->cmd_complete_arg,
-                                       PN533_FRAME_CMD_PARAMS_PTR(in_frame),
-                                       PN533_FRAME_CMD_PARAMS_LEN(in_frame));
-
+       rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error);
        if (rc != -EINPROGRESS)
                queue_work(dev->wq, &dev->cmd_work);
 }
@@ -526,46 +520,47 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
 static void pn533_recv_response(struct urb *urb)
 {
        struct pn533 *dev = urb->context;
-       struct pn533_frame *in_frame;
-
-       dev->wq_in_frame = NULL;
+       u8 *in_frame;
 
        switch (urb->status) {
        case 0:
-               /* success */
-               break;
+               break; /* success */
        case -ECONNRESET:
        case -ENOENT:
-       case -ESHUTDOWN:
-               nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
-                                               " status: %d", urb->status);
+               nfc_dev_dbg(&dev->interface->dev,
+                           "The urb has been canceled (status %d)",
+                           urb->status);
                dev->wq_in_error = urb->status;
                goto sched_wq;
+               break;
+       case -ESHUTDOWN:
        default:
-               nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
-                                                       " %d", urb->status);
+               nfc_dev_err(&dev->interface->dev,
+                           "Urb failure (status %d)", urb->status);
                dev->wq_in_error = urb->status;
                goto sched_wq;
        }
 
        in_frame = dev->in_urb->transfer_buffer;
 
-       if (!pn533_rx_frame_is_valid(in_frame)) {
+       nfc_dev_dbg(&dev->interface->dev, "Received a frame.");
+       print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1,
+                      in_frame, dev->ops->rx_frame_size(in_frame), false);
+
+       if (!dev->ops->rx_is_frame_valid(in_frame)) {
                nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
                dev->wq_in_error = -EIO;
                goto sched_wq;
        }
 
-       if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) {
-               nfc_dev_err(&dev->interface->dev, "The received frame is not "
-                                               "response to the last command");
+       if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) {
+               nfc_dev_err(&dev->interface->dev,
+                           "It it not the response to the last command");
                dev->wq_in_error = -EIO;
                goto sched_wq;
        }
 
-       nfc_dev_dbg(&dev->interface->dev, "Received a valid frame");
        dev->wq_in_error = 0;
-       dev->wq_in_frame = in_frame;
 
 sched_wq:
        queue_work(dev->wq, &dev->cmd_complete_work);
@@ -586,18 +581,19 @@ static void pn533_recv_ack(struct urb *urb)
 
        switch (urb->status) {
        case 0:
-               /* success */
-               break;
+               break; /* success */
        case -ECONNRESET:
        case -ENOENT:
-       case -ESHUTDOWN:
-               nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
-                                               " status: %d", urb->status);
+               nfc_dev_dbg(&dev->interface->dev,
+                           "The urb has been stopped (status %d)",
+                           urb->status);
                dev->wq_in_error = urb->status;
                goto sched_wq;
+               break;
+       case -ESHUTDOWN:
        default:
-               nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
-                                                       " %d", urb->status);
+               nfc_dev_err(&dev->interface->dev,
+                           "Urb failure (status %d)", urb->status);
                dev->wq_in_error = urb->status;
                goto sched_wq;
        }
@@ -610,12 +606,10 @@ static void pn533_recv_ack(struct urb *urb)
                goto sched_wq;
        }
 
-       nfc_dev_dbg(&dev->interface->dev, "Received a valid ack");
-
        rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
        if (rc) {
-               nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with"
-                                                       " result %d", rc);
+               nfc_dev_err(&dev->interface->dev,
+                           "usb_submit_urb failed with result %d", rc);
                dev->wq_in_error = rc;
                goto sched_wq;
        }
@@ -623,7 +617,6 @@ static void pn533_recv_ack(struct urb *urb)
        return;
 
 sched_wq:
-       dev->wq_in_frame = NULL;
        queue_work(dev->wq, &dev->cmd_complete_work);
 }
 
@@ -636,47 +629,46 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
 
 static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
 {
+       u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
+       /* spec 7.1.1.3:  Preamble, SoPC (2), ACK Code (2), Postamble */
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       pn533_tx_frame_ack(dev->out_frame);
-
-       dev->out_urb->transfer_buffer = dev->out_frame;
-       dev->out_urb->transfer_buffer_length = PN533_FRAME_ACK_SIZE;
+       dev->out_urb->transfer_buffer = ack;
+       dev->out_urb->transfer_buffer_length = sizeof(ack);
        rc = usb_submit_urb(dev->out_urb, flags);
 
        return rc;
 }
 
-static int __pn533_send_cmd_frame_async(struct pn533 *dev,
-                                       struct pn533_frame *out_frame,
-                                       struct pn533_frame *in_frame,
-                                       int in_frame_len,
+static int __pn533_send_frame_async(struct pn533 *dev,
+                                       struct sk_buff *out,
+                                       struct sk_buff *in,
+                                       int in_len,
                                        pn533_cmd_complete_t cmd_complete,
-                                       void *arg, gfp_t flags)
+                                       void *arg)
 {
        int rc;
 
-       nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x",
-                                               PN533_FRAME_CMD(out_frame));
-
-       dev->cmd = PN533_FRAME_CMD(out_frame);
+       dev->cmd = dev->ops->get_cmd_code(out->data);
        dev->cmd_complete = cmd_complete;
        dev->cmd_complete_arg = arg;
 
-       dev->out_urb->transfer_buffer = out_frame;
-       dev->out_urb->transfer_buffer_length =
-                               PN533_FRAME_SIZE(out_frame);
+       dev->out_urb->transfer_buffer = out->data;
+       dev->out_urb->transfer_buffer_length = out->len;
 
-       dev->in_urb->transfer_buffer = in_frame;
-       dev->in_urb->transfer_buffer_length = in_frame_len;
+       dev->in_urb->transfer_buffer = in->data;
+       dev->in_urb->transfer_buffer_length = in_len;
 
-       rc = usb_submit_urb(dev->out_urb, flags);
+       print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
+                      out->data, out->len, false);
+
+       rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
        if (rc)
                return rc;
 
-       rc = pn533_submit_urb_for_ack(dev, flags);
+       rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
        if (rc)
                goto error;
 
@@ -687,146 +679,325 @@ error:
        return rc;
 }
 
-static void pn533_wq_cmd(struct work_struct *work)
+static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
+                                 struct sk_buff *skb)
 {
-       struct pn533 *dev = container_of(work, struct pn533, cmd_work);
-       struct pn533_cmd *cmd;
+       /* payload is already there, just update datalen */
+       int payload_len = skb->len;
+       struct pn533_frame_ops *ops = dev->ops;
 
-       mutex_lock(&dev->cmd_lock);
 
-       if (list_empty(&dev->cmd_queue)) {
-               dev->cmd_pending = 0;
-               mutex_unlock(&dev->cmd_lock);
-               return;
-       }
+       skb_push(skb, ops->tx_header_len);
+       skb_put(skb, ops->tx_tail_len);
 
-       cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue);
+       ops->tx_frame_init(skb->data, cmd_code);
+       ops->tx_update_payload_len(skb->data, payload_len);
+       ops->tx_frame_finish(skb->data);
+}
 
-       list_del(&cmd->queue);
+struct pn533_send_async_complete_arg {
+       pn533_send_async_complete_t  complete_cb;
+       void *complete_cb_context;
+       struct sk_buff *resp;
+       struct sk_buff *req;
+};
 
-       mutex_unlock(&dev->cmd_lock);
+static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status)
+{
+       struct pn533_send_async_complete_arg *arg = _arg;
 
-       __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame,
-                                    cmd->in_frame_len, cmd->cmd_complete,
-                                    cmd->arg, cmd->flags);
+       struct sk_buff *req = arg->req;
+       struct sk_buff *resp = arg->resp;
 
-       kfree(cmd);
+       int rc;
+
+       dev_kfree_skb(req);
+
+       if (status < 0) {
+               arg->complete_cb(dev, arg->complete_cb_context,
+                                ERR_PTR(status));
+               dev_kfree_skb(resp);
+               kfree(arg);
+               return status;
+       }
+
+       skb_put(resp, dev->ops->rx_frame_size(resp->data));
+       skb_pull(resp, dev->ops->rx_header_len);
+       skb_trim(resp, resp->len - dev->ops->rx_tail_len);
+
+       rc = arg->complete_cb(dev, arg->complete_cb_context, resp);
+
+       kfree(arg);
+       return rc;
 }
 
-static int pn533_send_cmd_frame_async(struct pn533 *dev,
-                                       struct pn533_frame *out_frame,
-                                       struct pn533_frame *in_frame,
-                                       int in_frame_len,
-                                       pn533_cmd_complete_t cmd_complete,
-                                       void *arg, gfp_t flags)
+static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
+                             struct sk_buff *req, struct sk_buff *resp,
+                             int resp_len,
+                             pn533_send_async_complete_t complete_cb,
+                             void *complete_cb_context)
 {
        struct pn533_cmd *cmd;
+       struct pn533_send_async_complete_arg *arg;
        int rc = 0;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+       nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code);
+
+       arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+       if (!arg)
+               return -ENOMEM;
+
+       arg->complete_cb = complete_cb;
+       arg->complete_cb_context = complete_cb_context;
+       arg->resp = resp;
+       arg->req = req;
+
+       pn533_build_cmd_frame(dev, cmd_code, req);
 
        mutex_lock(&dev->cmd_lock);
 
        if (!dev->cmd_pending) {
-               rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
-                                                 in_frame_len, cmd_complete,
-                                                 arg, flags);
-               if (!rc)
-                       dev->cmd_pending = 1;
+               rc = __pn533_send_frame_async(dev, req, resp, resp_len,
+                                             pn533_send_async_complete, arg);
+               if (rc)
+                       goto error;
 
+               dev->cmd_pending = 1;
                goto unlock;
        }
 
-       nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__);
+       nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__,
+                   cmd_code);
 
-       cmd = kzalloc(sizeof(struct pn533_cmd), flags);
+       cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL);
        if (!cmd) {
                rc = -ENOMEM;
-               goto unlock;
+               goto error;
        }
 
        INIT_LIST_HEAD(&cmd->queue);
-       cmd->out_frame = out_frame;
-       cmd->in_frame = in_frame;
-       cmd->in_frame_len = in_frame_len;
-       cmd->cmd_complete = cmd_complete;
+       cmd->cmd_code = cmd_code;
+       cmd->req = req;
+       cmd->resp = resp;
+       cmd->resp_len = resp_len;
        cmd->arg = arg;
-       cmd->flags = flags;
 
        list_add_tail(&cmd->queue, &dev->cmd_queue);
 
+       goto unlock;
+
+error:
+       kfree(arg);
 unlock:
        mutex_unlock(&dev->cmd_lock);
+       return rc;
+}
+
+static int pn533_send_data_async(struct pn533 *dev, u8 cmd_code,
+                                struct sk_buff *req,
+                                pn533_send_async_complete_t complete_cb,
+                                void *complete_cb_context)
+{
+       struct sk_buff *resp;
+       int rc;
+       int  resp_len = dev->ops->rx_header_len +
+                       dev->ops->max_payload_len +
+                       dev->ops->rx_tail_len;
+
+       resp = nfc_alloc_recv_skb(resp_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+                               complete_cb_context);
+       if (rc)
+               dev_kfree_skb(resp);
 
        return rc;
 }
 
-struct pn533_sync_cmd_response {
+static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code,
+                               struct sk_buff *req,
+                               pn533_send_async_complete_t complete_cb,
+                               void *complete_cb_context)
+{
+       struct sk_buff *resp;
        int rc;
-       struct completion done;
-};
+       int  resp_len = dev->ops->rx_header_len +
+                       dev->ops->max_payload_len +
+                       dev->ops->rx_tail_len;
+
+       resp = alloc_skb(resp_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+                               complete_cb_context);
+       if (rc)
+               dev_kfree_skb(resp);
 
-static int pn533_sync_cmd_complete(struct pn533 *dev, void *_arg,
-                                       u8 *params, int params_len)
+       return rc;
+}
+
+/*
+ * pn533_send_cmd_direct_async
+ *
+ * The function sends a piority cmd directly to the chip omiting the cmd
+ * queue. It's intended to be used by chaining mechanism of received responses
+ * where the host has to request every single chunk of data before scheduling
+ * next cmd from the queue.
+ */
+static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
+                                      struct sk_buff *req,
+                                      pn533_send_async_complete_t complete_cb,
+                                      void *complete_cb_context)
 {
-       struct pn533_sync_cmd_response *arg = _arg;
+       struct pn533_send_async_complete_arg *arg;
+       struct sk_buff *resp;
+       int rc;
+       int resp_len = dev->ops->rx_header_len +
+                      dev->ops->max_payload_len +
+                      dev->ops->rx_tail_len;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+       resp = alloc_skb(resp_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+       if (!arg) {
+               dev_kfree_skb(resp);
+               return -ENOMEM;
+       }
 
-       arg->rc = 0;
+       arg->complete_cb = complete_cb;
+       arg->complete_cb_context = complete_cb_context;
+       arg->resp = resp;
+       arg->req = req;
 
-       if (params_len < 0) /* error */
-               arg->rc = params_len;
+       pn533_build_cmd_frame(dev, cmd_code, req);
 
+       rc = __pn533_send_frame_async(dev, req, resp, resp_len,
+                                     pn533_send_async_complete, arg);
+       if (rc < 0) {
+               dev_kfree_skb(resp);
+               kfree(arg);
+       }
+
+       return rc;
+}
+
+static void pn533_wq_cmd(struct work_struct *work)
+{
+       struct pn533 *dev = container_of(work, struct pn533, cmd_work);
+       struct pn533_cmd *cmd;
+
+       mutex_lock(&dev->cmd_lock);
+
+       if (list_empty(&dev->cmd_queue)) {
+               dev->cmd_pending = 0;
+               mutex_unlock(&dev->cmd_lock);
+               return;
+       }
+
+       cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue);
+
+       list_del(&cmd->queue);
+
+       mutex_unlock(&dev->cmd_lock);
+
+       __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len,
+                                pn533_send_async_complete, cmd->arg);
+
+       kfree(cmd);
+}
+
+struct pn533_sync_cmd_response {
+       struct sk_buff *resp;
+       struct completion done;
+};
+
+static int pn533_send_sync_complete(struct pn533 *dev, void *_arg,
+                                   struct sk_buff *resp)
+{
+       struct pn533_sync_cmd_response *arg = _arg;
+
+       arg->resp = resp;
        complete(&arg->done);
 
        return 0;
 }
 
-static int pn533_send_cmd_frame_sync(struct pn533 *dev,
-                                               struct pn533_frame *out_frame,
-                                               struct pn533_frame *in_frame,
-                                               int in_frame_len)
+/*  pn533_send_cmd_sync
+ *
+ *  Please note the req parameter is freed inside the function to
+ *  limit a number of return value interpretations by the caller.
+ *
+ *  1. negative in case of error during TX path -> req should be freed
+ *
+ *  2. negative in case of error during RX path -> req should not be freed
+ *     as it's been already freed at the begining of RX path by
+ *     async_complete_cb.
+ *
+ *  3. valid pointer in case of succesfult RX path
+ *
+ *  A caller has to check a return value with IS_ERR macro. If the test pass,
+ *  the returned pointer is valid.
+ *
+ * */
+static struct sk_buff *pn533_send_cmd_sync(struct pn533 *dev, u8 cmd_code,
+                                              struct sk_buff *req)
 {
        int rc;
        struct pn533_sync_cmd_response arg;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
        init_completion(&arg.done);
 
-       rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, in_frame_len,
-                               pn533_sync_cmd_complete, &arg, GFP_KERNEL);
-       if (rc)
-               return rc;
+       rc = pn533_send_cmd_async(dev, cmd_code, req,
+                                 pn533_send_sync_complete, &arg);
+       if (rc) {
+               dev_kfree_skb(req);
+               return ERR_PTR(rc);
+       }
 
        wait_for_completion(&arg.done);
 
-       return arg.rc;
+       return arg.resp;
 }
 
 static void pn533_send_complete(struct urb *urb)
 {
        struct pn533 *dev = urb->context;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
        switch (urb->status) {
        case 0:
-               /* success */
-               break;
+               break; /* success */
        case -ECONNRESET:
        case -ENOENT:
-       case -ESHUTDOWN:
-               nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
-                                               " status: %d", urb->status);
+               nfc_dev_dbg(&dev->interface->dev,
+                           "The urb has been stopped (status %d)",
+                           urb->status);
                break;
+       case -ESHUTDOWN:
        default:
-               nfc_dev_dbg(&dev->interface->dev, "Nonzero urb status received:"
-                                                       " %d", urb->status);
+               nfc_dev_err(&dev->interface->dev,
+                           "Urb failure (status %d)", urb->status);
        }
 }
 
+static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size)
+{
+       struct sk_buff *skb;
+
+       skb = alloc_skb(dev->ops->tx_header_len +
+                       size +
+                       dev->ops->tx_tail_len, GFP_KERNEL);
+
+       if (skb)
+               skb_reserve(skb, dev->ops->tx_header_len);
+
+       return skb;
+}
+
 struct pn533_target_type_a {
        __be16 sens_res;
        u8 sel_res;
@@ -867,9 +1038,9 @@ static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a,
        platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res);
 
        if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-                       platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
-                       (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-                       platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+            platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+           (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+            platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
                return false;
 
        /* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */
@@ -884,7 +1055,7 @@ static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data,
 {
        struct pn533_target_type_a *tgt_type_a;
 
-       tgt_type_a = (struct pn533_target_type_a *) tgt_data;
+       tgt_type_a = (struct pn533_target_type_a *)tgt_data;
 
        if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len))
                return -EPROTO;
@@ -942,14 +1113,13 @@ static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data,
 {
        struct pn533_target_felica *tgt_felica;
 
-       tgt_felica = (struct pn533_target_felica *) tgt_data;
+       tgt_felica = (struct pn533_target_felica *)tgt_data;
 
        if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len))
                return -EPROTO;
 
-       if (tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1 &&
-                                       tgt_felica->nfcid2[1] ==
-                                       PN533_FELICA_SENSF_NFCID2_DEP_B2)
+       if ((tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1) &&
+           (tgt_felica->nfcid2[1] == PN533_FELICA_SENSF_NFCID2_DEP_B2))
                nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
        else
                nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK;
@@ -979,9 +1149,9 @@ static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel,
        platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res);
 
        if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-                       platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
-                       (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-                       platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+            platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+           (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+            platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
                return false;
 
        return true;
@@ -992,7 +1162,7 @@ static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data,
 {
        struct pn533_target_jewel *tgt_jewel;
 
-       tgt_jewel = (struct pn533_target_jewel *) tgt_data;
+       tgt_jewel = (struct pn533_target_jewel *)tgt_data;
 
        if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len))
                return -EPROTO;
@@ -1051,7 +1221,7 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data,
 {
        struct pn533_target_type_b *tgt_type_b;
 
-       tgt_type_b = (struct pn533_target_type_b *) tgt_data;
+       tgt_type_b = (struct pn533_target_type_b *)tgt_data;
 
        if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len))
                return -EPROTO;
@@ -1061,50 +1231,37 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data,
        return 0;
 }
 
-struct pn533_poll_response {
-       u8 nbtg;
-       u8 tg;
-       u8 target_data[];
-} __packed;
-
-static int pn533_target_found(struct pn533 *dev,
-                       struct pn533_poll_response *resp, int resp_len)
+static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata,
+                             int tgdata_len)
 {
-       int target_data_len;
        struct nfc_target nfc_tgt;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s - modulation=%d", __func__,
-                                                       dev->poll_mod_curr);
+                   dev->poll_mod_curr);
 
-       if (resp->tg != 1)
+       if (tg != 1)
                return -EPROTO;
 
        memset(&nfc_tgt, 0, sizeof(struct nfc_target));
 
-       target_data_len = resp_len - sizeof(struct pn533_poll_response);
-
        switch (dev->poll_mod_curr) {
        case PN533_POLL_MOD_106KBPS_A:
-               rc = pn533_target_found_type_a(&nfc_tgt, resp->target_data,
-                                                       target_data_len);
+               rc = pn533_target_found_type_a(&nfc_tgt, tgdata, tgdata_len);
                break;
        case PN533_POLL_MOD_212KBPS_FELICA:
        case PN533_POLL_MOD_424KBPS_FELICA:
-               rc = pn533_target_found_felica(&nfc_tgt, resp->target_data,
-                                                       target_data_len);
+               rc = pn533_target_found_felica(&nfc_tgt, tgdata, tgdata_len);
                break;
        case PN533_POLL_MOD_106KBPS_JEWEL:
-               rc = pn533_target_found_jewel(&nfc_tgt, resp->target_data,
-                                                       target_data_len);
+               rc = pn533_target_found_jewel(&nfc_tgt, tgdata, tgdata_len);
                break;
        case PN533_POLL_MOD_847KBPS_B:
-               rc = pn533_target_found_type_b(&nfc_tgt, resp->target_data,
-                                                       target_data_len);
+               rc = pn533_target_found_type_b(&nfc_tgt, tgdata, tgdata_len);
                break;
        default:
-               nfc_dev_err(&dev->interface->dev, "Unknown current poll"
-                                                               " modulation");
+               nfc_dev_err(&dev->interface->dev,
+                           "Unknown current poll modulation");
                return -EPROTO;
        }
 
@@ -1112,13 +1269,14 @@ static int pn533_target_found(struct pn533 *dev,
                return rc;
 
        if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) {
-               nfc_dev_dbg(&dev->interface->dev, "The target found does not"
-                                               " have the desired protocol");
+               nfc_dev_dbg(&dev->interface->dev,
+                           "The Tg found doesn't have the desired protocol");
                return -EAGAIN;
        }
 
-       nfc_dev_dbg(&dev->interface->dev, "Target found - supported protocols: "
-                                       "0x%x", nfc_tgt.supported_protocols);
+       nfc_dev_dbg(&dev->interface->dev,
+                   "Target found - supported protocols: 0x%x",
+                   nfc_tgt.supported_protocols);
 
        dev->tgt_available_prots = nfc_tgt.supported_protocols;
 
@@ -1140,7 +1298,7 @@ static void pn533_poll_reset_mod_list(struct pn533 *dev)
 static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
 {
        dev->poll_mod_active[dev->poll_mod_count] =
-               (struct pn533_poll_modulations *) &poll_mod[mod_index];
+               (struct pn533_poll_modulations *)&poll_mod[mod_index];
        dev->poll_mod_count++;
 }
 
@@ -1149,13 +1307,13 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,
 {
        pn533_poll_reset_mod_list(dev);
 
-       if (im_protocols & NFC_PROTO_MIFARE_MASK
-           || im_protocols & NFC_PROTO_ISO14443_MASK
-           || im_protocols & NFC_PROTO_NFC_DEP_MASK)
+       if ((im_protocols & NFC_PROTO_MIFARE_MASK) ||
+           (im_protocols & NFC_PROTO_ISO14443_MASK) ||
+           (im_protocols & NFC_PROTO_NFC_DEP_MASK))
                pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
 
-       if (im_protocols & NFC_PROTO_FELICA_MASK
-           || im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+       if (im_protocols & NFC_PROTO_FELICA_MASK ||
+           im_protocols & NFC_PROTO_NFC_DEP_MASK) {
                pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
                pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
        }
@@ -1170,16 +1328,20 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,
                pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
 }
 
-static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len)
+static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp)
 {
-       struct pn533_poll_response *resp;
-       int rc;
+       u8 nbtg, tg, *tgdata;
+       int rc, tgdata_len;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       resp = (struct pn533_poll_response *) params;
-       if (resp->nbtg) {
-               rc = pn533_target_found(dev, resp, params_len);
+       nbtg = resp->data[0];
+       tg = resp->data[1];
+       tgdata = &resp->data[2];
+       tgdata_len = resp->len - 2;  /* nbtg + tg */
+
+       if (nbtg) {
+               rc = pn533_target_found(dev, tg, tgdata, tgdata_len);
 
                /* We must stop the poll after a valid target found */
                if (rc == 0) {
@@ -1191,158 +1353,134 @@ static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_l
        return -EAGAIN;
 }
 
-static int pn533_init_target_frame(struct pn533_frame *frame,
-                                  u8 *gb, size_t gb_len)
+static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev)
 {
-       struct pn533_cmd_init_target *cmd;
-       size_t cmd_len;
+       struct sk_buff *skb;
+       u8 *felica, *nfcid3, *gb;
+
+       u8 *gbytes = dev->gb;
+       size_t gbytes_len = dev->gb_len;
+
        u8 felica_params[18] = {0x1, 0xfe, /* DEP */
                                0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
                                0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
                                0xff, 0xff}; /* System code */
+
        u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
                               0x0, 0x0, 0x0,
                               0x40}; /* SEL_RES for DEP */
 
-       cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
-       cmd = kzalloc(cmd_len, GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
+       unsigned int skb_len = 36 + /* mode (1), mifare (6),
+                                      felica (18), nfcid3 (10), gb_len (1) */
+                              gbytes_len +
+                              1;  /* len Tk*/
 
-       pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
+       skb = pn533_alloc_skb(dev, skb_len);
+       if (!skb)
+               return NULL;
 
        /* DEP support only */
-       cmd->mode |= PN533_INIT_TARGET_DEP;
+       *skb_put(skb, 1) |= PN533_INIT_TARGET_DEP;
+
+       /* MIFARE params */
+       memcpy(skb_put(skb, 6), mifare_params, 6);
 
        /* Felica params */
-       memcpy(cmd->felica, felica_params, 18);
-       get_random_bytes(cmd->felica + 2, 6);
+       felica = skb_put(skb, 18);
+       memcpy(felica, felica_params, 18);
+       get_random_bytes(felica + 2, 6);
 
        /* NFCID3 */
-       memset(cmd->nfcid3, 0, 10);
-       memcpy(cmd->nfcid3, cmd->felica, 8);
-
-       /* MIFARE params */
-       memcpy(cmd->mifare, mifare_params, 6);
+       nfcid3 = skb_put(skb, 10);
+       memset(nfcid3, 0, 10);
+       memcpy(nfcid3, felica, 8);
 
        /* General bytes */
-       cmd->gb_len = gb_len;
-       memcpy(cmd->gb, gb, gb_len);
-
-       /* Len Tk */
-       cmd->gb[gb_len] = 0;
-
-       memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
+       *skb_put(skb, 1) = gbytes_len;
 
-       frame->datalen += cmd_len;
+       gb = skb_put(skb, gbytes_len);
+       memcpy(gb, gbytes, gbytes_len);
 
-       pn533_tx_frame_finish(frame);
-
-       kfree(cmd);
+       /* Len Tk */
+       *skb_put(skb, 1) = 0;
 
-       return 0;
+       return skb;
 }
 
-#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_HEAD_LEN 1
 #define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
 static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
-                                     u8 *params, int params_len)
+                                     struct sk_buff *resp)
 {
-       struct sk_buff *skb_resp = arg;
-       struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
+       u8 status;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       if (params_len < 0) {
-               nfc_dev_err(&dev->interface->dev,
-                           "Error %d when starting as a target",
-                           params_len);
+       if (IS_ERR(resp))
+               return PTR_ERR(resp);
 
-               return params_len;
-       }
+       status = resp->data[0];
+       skb_pull(resp, sizeof(status));
 
-       if (params_len > 0 && params[0] != 0) {
+       if (status != 0) {
                nfc_tm_deactivated(dev->nfc_dev);
-
                dev->tgt_mode = 0;
-
-               kfree_skb(skb_resp);
+               dev_kfree_skb(resp);
                return 0;
        }
 
-       skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
-       skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
-       skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
-
-       return nfc_tm_data_received(dev->nfc_dev, skb_resp);
+       return nfc_tm_data_received(dev->nfc_dev, resp);
 }
 
 static void pn533_wq_tg_get_data(struct work_struct *work)
 {
        struct pn533 *dev = container_of(work, struct pn533, tg_work);
-       struct pn533_frame *in_frame;
-       struct sk_buff *skb_resp;
-       size_t skb_resp_len;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+       struct sk_buff *skb;
+       int rc;
 
-       skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
-               PN533_CMD_DATAEXCH_DATA_MAXLEN +
-               PN533_FRAME_TAIL_SIZE;
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
-       if (!skb_resp)
+       skb = pn533_alloc_skb(dev, 0);
+       if (!skb)
                return;
 
-       in_frame = (struct pn533_frame *)skb_resp->data;
+       rc = pn533_send_data_async(dev, PN533_CMD_TG_GET_DATA, skb,
+                                  pn533_tm_get_data_complete, NULL);
 
-       pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA);
-       pn533_tx_frame_finish(dev->out_frame);
-
-       pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame,
-                                  skb_resp_len,
-                                  pn533_tm_get_data_complete,
-                                  skb_resp, GFP_KERNEL);
+       if (rc < 0)
+               dev_kfree_skb(skb);
 
        return;
 }
 
 #define ATR_REQ_GB_OFFSET 17
-static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len)
+static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp)
 {
-       struct pn533_cmd_init_target_response *resp;
-       u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
+       u8 mode, *cmd, comm_mode = NFC_COMM_PASSIVE, *gb;
        size_t gb_len;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       if (params_len < 0) {
-               nfc_dev_err(&dev->interface->dev,
-                           "Error %d when starting as a target",
-                           params_len);
-
-               return params_len;
-       }
-
-       if (params_len < ATR_REQ_GB_OFFSET + 1)
+       if (resp->len < ATR_REQ_GB_OFFSET + 1)
                return -EINVAL;
 
-       resp = (struct pn533_cmd_init_target_response *) params;
+       mode = resp->data[0];
+       cmd = &resp->data[1];
 
-       nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
-                   resp->mode, params_len);
+       nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x len %d\n",
+                   mode, resp->len);
 
-       frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
-       if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
+       if ((mode & PN533_INIT_TARGET_RESP_FRAME_MASK) ==
+           PN533_INIT_TARGET_RESP_ACTIVE)
                comm_mode = NFC_COMM_ACTIVE;
 
-       /* Again, only DEP */
-       if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
+       if ((mode & PN533_INIT_TARGET_RESP_DEP) == 0)  /* Only DEP supported */
                return -EOPNOTSUPP;
 
-       gb = resp->cmd + ATR_REQ_GB_OFFSET;
-       gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
+       gb = cmd + ATR_REQ_GB_OFFSET;
+       gb_len = resp->len - (ATR_REQ_GB_OFFSET + 1);
 
        rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
                              comm_mode, gb, gb_len);
@@ -1353,7 +1491,6 @@ static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_
        }
 
        dev->tgt_mode = 1;
-
        queue_work(dev->wq, &dev->tg_work);
 
        return 0;
@@ -1361,7 +1498,7 @@ static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_
 
 static void pn533_listen_mode_timer(unsigned long data)
 {
-       struct pn533 *dev = (struct pn533 *) data;
+       struct pn533 *dev = (struct pn533 *)data;
 
        nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
 
@@ -1376,88 +1513,104 @@ static void pn533_listen_mode_timer(unsigned long data)
 }
 
 static int pn533_poll_complete(struct pn533 *dev, void *arg,
-                              u8 *params, int params_len)
+                              struct sk_buff *resp)
 {
        struct pn533_poll_modulations *cur_mod;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       if (params_len == -ENOENT) {
-               if (dev->poll_mod_count != 0)
-                       return 0;
-
-               nfc_dev_err(&dev->interface->dev,
-                           "Polling operation has been stopped");
-
-               goto stop_poll;
-       }
+       if (IS_ERR(resp)) {
+               rc = PTR_ERR(resp);
 
-       if (params_len < 0) {
-               nfc_dev_err(&dev->interface->dev,
-                           "Error %d when running poll", params_len);
+               nfc_dev_err(&dev->interface->dev, "%s  Poll complete error %d",
+                           __func__, rc);
 
-               goto stop_poll;
+               if (rc == -ENOENT) {
+                       if (dev->poll_mod_count != 0)
+                               return rc;
+                       else
+                               goto stop_poll;
+               } else if (rc < 0) {
+                       nfc_dev_err(&dev->interface->dev,
+                                   "Error %d when running poll", rc);
+                       goto stop_poll;
+               }
        }
 
        cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
 
-       if (cur_mod->len == 0) {
+       if (cur_mod->len == 0) { /* Target mode */
                del_timer(&dev->listen_timer);
-
-               return pn533_init_target_complete(dev, params, params_len);
-       } else {
-               rc = pn533_start_poll_complete(dev, params, params_len);
-               if (!rc)
-                       return rc;
+               rc = pn533_init_target_complete(dev, resp);
+               goto done;
        }
 
-       pn533_poll_next_mod(dev);
+       /* Initiator mode */
+       rc = pn533_start_poll_complete(dev, resp);
+       if (!rc)
+               goto done;
 
+       pn533_poll_next_mod(dev);
        queue_work(dev->wq, &dev->poll_work);
 
-       return 0;
+done:
+       dev_kfree_skb(resp);
+       return rc;
 
 stop_poll:
+       nfc_dev_err(&dev->interface->dev, "Polling operation has been stopped");
+
        pn533_poll_reset_mod_list(dev);
        dev->poll_protocols = 0;
-       return 0;
+       return rc;
 }
 
-static void pn533_build_poll_frame(struct pn533 *dev,
-                                  struct pn533_frame *frame,
-                                  struct pn533_poll_modulations *mod)
+static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533 *dev,
+                                       struct pn533_poll_modulations *mod)
 {
-       nfc_dev_dbg(&dev->interface->dev, "mod len %d\n", mod->len);
+       struct sk_buff *skb;
 
-       if (mod->len == 0) {
-               /* Listen mode */
-               pn533_init_target_frame(frame, dev->gb, dev->gb_len);
-       } else {
-               /* Polling mode */
-               pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
+       skb = pn533_alloc_skb(dev, mod->len);
+       if (!skb)
+               return NULL;
 
-               memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
-               frame->datalen += mod->len;
+       memcpy(skb_put(skb, mod->len), &mod->data, mod->len);
 
-               pn533_tx_frame_finish(frame);
-       }
+       return skb;
 }
 
 static int pn533_send_poll_frame(struct pn533 *dev)
 {
-       struct pn533_poll_modulations *cur_mod;
+       struct pn533_poll_modulations *mod;
+       struct sk_buff *skb;
        int rc;
+       u8 cmd_code;
 
-       cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+       mod = dev->poll_mod_active[dev->poll_mod_curr];
 
-       pn533_build_poll_frame(dev, dev->out_frame, cur_mod);
+       nfc_dev_dbg(&dev->interface->dev, "%s mod len %d\n",
+                   __func__, mod->len);
 
-       rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-                               dev->in_maxlen, pn533_poll_complete,
-                               NULL, GFP_KERNEL);
-       if (rc)
+       if (mod->len == 0) {  /* Listen mode */
+               cmd_code = PN533_CMD_TG_INIT_AS_TARGET;
+               skb = pn533_alloc_poll_tg_frame(dev);
+       } else {  /* Polling mode */
+               cmd_code =  PN533_CMD_IN_LIST_PASSIVE_TARGET;
+               skb = pn533_alloc_poll_in_frame(dev, mod);
+       }
+
+       if (!skb) {
+               nfc_dev_err(&dev->interface->dev, "Failed to allocate skb.");
+               return -ENOMEM;
+       }
+
+       rc = pn533_send_cmd_async(dev, cmd_code, skb, pn533_poll_complete,
+                                 NULL);
+       if (rc < 0) {
+               dev_kfree_skb(skb);
                nfc_dev_err(&dev->interface->dev, "Polling loop error %d", rc);
+       }
 
        return rc;
 }
@@ -1533,8 +1686,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
        del_timer(&dev->listen_timer);
 
        if (!dev->poll_mod_count) {
-               nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
-                                                               " running");
+               nfc_dev_dbg(&dev->interface->dev,
+                           "Polling operation was not running");
                return;
        }
 
@@ -1549,38 +1702,38 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
 
 static int pn533_activate_target_nfcdep(struct pn533 *dev)
 {
-       struct pn533_cmd_activate_param param;
-       struct pn533_cmd_activate_response *resp;
+       struct pn533_cmd_activate_response *rsp;
        u16 gt_len;
        int rc;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+       struct sk_buff *skb;
+       struct sk_buff *resp;
 
-       pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_ATR);
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       param.tg = 1;
-       param.next = 0;
-       memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &param,
-                               sizeof(struct pn533_cmd_activate_param));
-       dev->out_frame->datalen += sizeof(struct pn533_cmd_activate_param);
+       skb = pn533_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/
+       if (!skb)
+               return -ENOMEM;
 
-       pn533_tx_frame_finish(dev->out_frame);
+       *skb_put(skb, sizeof(u8)) = 1; /* TG */
+       *skb_put(skb, sizeof(u8)) = 0; /* Next */
 
-       rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-                                                               dev->in_maxlen);
-       if (rc)
-               return rc;
+       resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_ATR, skb);
+       if (IS_ERR(resp))
+               return PTR_ERR(resp);
 
-       resp = (struct pn533_cmd_activate_response *)
-                               PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
-       rc = resp->status & PN533_CMD_RET_MASK;
-       if (rc != PN533_CMD_RET_SUCCESS)
+       rsp = (struct pn533_cmd_activate_response *)resp->data;
+       rc = rsp->status & PN533_CMD_RET_MASK;
+       if (rc != PN533_CMD_RET_SUCCESS) {
+               dev_kfree_skb(resp);
                return -EIO;
+       }
 
        /* ATR_RES general bytes are located at offset 16 */
-       gt_len = PN533_FRAME_CMD_PARAMS_LEN(dev->in_frame) - 16;
-       rc = nfc_set_remote_general_bytes(dev->nfc_dev, resp->gt, gt_len);
+       gt_len = resp->len - 16;
+       rc = nfc_set_remote_general_bytes(dev->nfc_dev, rsp->gt, gt_len);
 
+       dev_kfree_skb(resp);
        return rc;
 }
 
@@ -1591,38 +1744,38 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev,
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s - protocol=%u", __func__,
-                                                               protocol);
+                   protocol);
 
        if (dev->poll_mod_count) {
-               nfc_dev_err(&dev->interface->dev, "Cannot activate while"
-                                                               " polling");
+               nfc_dev_err(&dev->interface->dev,
+                           "Cannot activate while polling");
                return -EBUSY;
        }
 
        if (dev->tgt_active_prot) {
-               nfc_dev_err(&dev->interface->dev, "There is already an active"
-                                                               " target");
+               nfc_dev_err(&dev->interface->dev,
+                           "There is already an active target");
                return -EBUSY;
        }
 
        if (!dev->tgt_available_prots) {
-               nfc_dev_err(&dev->interface->dev, "There is no available target"
-                                                               " to activate");
+               nfc_dev_err(&dev->interface->dev,
+                           "There is no available target to activate");
                return -EINVAL;
        }
 
        if (!(dev->tgt_available_prots & (1 << protocol))) {
-               nfc_dev_err(&dev->interface->dev, "The target does not support"
-                                       " the requested protocol %u", protocol);
+               nfc_dev_err(&dev->interface->dev,
+                           "Target doesn't support requested proto %u",
+                           protocol);
                return -EINVAL;
        }
 
        if (protocol == NFC_PROTO_NFC_DEP) {
                rc = pn533_activate_target_nfcdep(dev);
                if (rc) {
-                       nfc_dev_err(&dev->interface->dev, "Error %d when"
-                                               " activating target with"
-                                               " NFC_DEP protocol", rc);
+                       nfc_dev_err(&dev->interface->dev,
+                                   "Activating target with DEP failed %d", rc);
                        return rc;
                }
        }
@@ -1637,8 +1790,10 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
                                    struct nfc_target *target)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-       u8 tg;
-       u8 status;
+
+       struct sk_buff *skb;
+       struct sk_buff *resp;
+
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@@ -1649,83 +1804,69 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
        }
 
        dev->tgt_active_prot = 0;
-
        skb_queue_purge(&dev->resp_q);
 
-       pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE);
-
-       tg = 1;
-       memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &tg, sizeof(u8));
-       dev->out_frame->datalen += sizeof(u8);
+       skb = pn533_alloc_skb(dev, sizeof(u8));
+       if (!skb)
+               return;
 
-       pn533_tx_frame_finish(dev->out_frame);
+       *skb_put(skb, 1) = 1; /* TG*/
 
-       rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-                                                               dev->in_maxlen);
-       if (rc) {
-               nfc_dev_err(&dev->interface->dev, "Error when sending release"
-                                               " command to the controller");
+       resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_RELEASE, skb);
+       if (IS_ERR(resp))
                return;
-       }
 
-       status = PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame)[0];
-       rc = status & PN533_CMD_RET_MASK;
+       rc = resp->data[0] & PN533_CMD_RET_MASK;
        if (rc != PN533_CMD_RET_SUCCESS)
-               nfc_dev_err(&dev->interface->dev, "Error 0x%x when releasing"
-                                                       " the target", rc);
+               nfc_dev_err(&dev->interface->dev,
+                           "Error 0x%x when releasing the target", rc);
 
+       dev_kfree_skb(resp);
        return;
 }
 
 
 static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
-                                               u8 *params, int params_len)
+                                        struct sk_buff *resp)
 {
-       struct pn533_cmd_jump_dep_response *resp;
-       struct nfc_target nfc_target;
+       struct pn533_cmd_jump_dep_response *rsp;
        u8 target_gt_len;
        int rc;
-       struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg;
-       u8 active = cmd->active;
+       u8 active = *(u8 *)arg;
 
        kfree(arg);
 
-       if (params_len == -ENOENT) {
-               nfc_dev_dbg(&dev->interface->dev, "");
-               return 0;
-       }
-
-       if (params_len < 0) {
-               nfc_dev_err(&dev->interface->dev,
-                               "Error %d when bringing DEP link up",
-                                                               params_len);
-               return 0;
-       }
+       if (IS_ERR(resp))
+               return PTR_ERR(resp);
 
        if (dev->tgt_available_prots &&
            !(dev->tgt_available_prots & (1 << NFC_PROTO_NFC_DEP))) {
                nfc_dev_err(&dev->interface->dev,
-                       "The target does not support DEP");
-               return -EINVAL;
+                           "The target does not support DEP");
+               rc =  -EINVAL;
+               goto error;
        }
 
-       resp = (struct pn533_cmd_jump_dep_response *) params;
-       rc = resp->status & PN533_CMD_RET_MASK;
+       rsp = (struct pn533_cmd_jump_dep_response *)resp->data;
+
+       rc = rsp->status & PN533_CMD_RET_MASK;
        if (rc != PN533_CMD_RET_SUCCESS) {
                nfc_dev_err(&dev->interface->dev,
-                               "Bringing DEP link up failed %d", rc);
-               return 0;
+                           "Bringing DEP link up failed %d", rc);
+               goto error;
        }
 
        if (!dev->tgt_available_prots) {
+               struct nfc_target nfc_target;
+
                nfc_dev_dbg(&dev->interface->dev, "Creating new target");
 
                nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
                nfc_target.nfcid1_len = 10;
-               memcpy(nfc_target.nfcid1, resp->nfcid3t, nfc_target.nfcid1_len);
+               memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len);
                rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1);
                if (rc)
-                       return 0;
+                       goto error;
 
                dev->tgt_available_prots = 0;
        }
@@ -1733,15 +1874,17 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
        dev->tgt_active_prot = NFC_PROTO_NFC_DEP;
 
        /* ATR_RES general bytes are located at offset 17 */
-       target_gt_len = PN533_FRAME_CMD_PARAMS_LEN(dev->in_frame) - 17;
+       target_gt_len = resp->len - 17;
        rc = nfc_set_remote_general_bytes(dev->nfc_dev,
-                                               resp->gt, target_gt_len);
+                                         rsp->gt, target_gt_len);
        if (rc == 0)
                rc = nfc_dep_link_is_up(dev->nfc_dev,
-                                               dev->nfc_dev->targets[0].idx,
-                                               !active, NFC_RF_INITIATOR);
+                                       dev->nfc_dev->targets[0].idx,
+                                       !active, NFC_RF_INITIATOR);
 
-       return 0;
+error:
+       dev_kfree_skb(resp);
+       return rc;
 }
 
 static int pn533_mod_to_baud(struct pn533 *dev)
@@ -1760,25 +1903,26 @@ static int pn533_mod_to_baud(struct pn533 *dev)
 
 #define PASSIVE_DATA_LEN 5
 static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
-                            u8 comm_mode, u8gb, size_t gb_len)
+                            u8 comm_mode, u8 *gb, size_t gb_len)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-       struct pn533_cmd_jump_dep *cmd;
-       u8 cmd_len, *data_ptr;
+       struct sk_buff *skb;
+       int rc, baud, skb_len;
+       u8 *next, *arg;
+
        u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
-       int rc, baud;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
        if (dev->poll_mod_count) {
                nfc_dev_err(&dev->interface->dev,
-                               "Cannot bring the DEP link up while polling");
+                           "Cannot bring the DEP link up while polling");
                return -EBUSY;
        }
 
        if (dev->tgt_active_prot) {
                nfc_dev_err(&dev->interface->dev,
-                               "There is already an active target");
+                           "There is already an active target");
                return -EBUSY;
        }
 
@@ -1789,43 +1933,48 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
                return baud;
        }
 
-       cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
+       skb_len = 3 + gb_len; /* ActPass + BR + Next */
        if (comm_mode == NFC_COMM_PASSIVE)
-               cmd_len += PASSIVE_DATA_LEN;
+               skb_len += PASSIVE_DATA_LEN;
 
-       cmd = kzalloc(cmd_len, GFP_KERNEL);
-       if (cmd == NULL)
+       skb = pn533_alloc_skb(dev, skb_len);
+       if (!skb)
                return -ENOMEM;
 
-       pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP);
+       *skb_put(skb, 1) = !comm_mode;  /* ActPass */
+       *skb_put(skb, 1) = baud;  /* Baud rate */
 
-       cmd->active = !comm_mode;
-       cmd->next = 0;
-       cmd->baud = baud;
-       data_ptr = cmd->data;
-       if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
-               memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
-               cmd->next |= 1;
-               data_ptr += PASSIVE_DATA_LEN;
+       next = skb_put(skb, 1);  /* Next */
+       *next = 0;
+
+       if (comm_mode == NFC_COMM_PASSIVE && baud > 0) {
+               memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data,
+                      PASSIVE_DATA_LEN);
+               *next |= 1;
        }
 
        if (gb != NULL && gb_len > 0) {
-               cmd->next |= 4; /* We have some Gi */
-               memcpy(data_ptr, gb, gb_len);
+               memcpy(skb_put(skb, gb_len), gb, gb_len);
+               *next |= 4; /* We have some Gi */
        } else {
-               cmd->next = 0;
+               *next = 0;
        }
 
-       memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), cmd, cmd_len);
-       dev->out_frame->datalen += cmd_len;
+       arg = kmalloc(sizeof(*arg), GFP_KERNEL);
+       if (!arg) {
+               dev_kfree_skb(skb);
+               return -ENOMEM;
+       }
 
-       pn533_tx_frame_finish(dev->out_frame);
+       *arg = !comm_mode;
 
-       rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-                               dev->in_maxlen, pn533_in_dep_link_up_complete,
-                               cmd, GFP_KERNEL);
-       if (rc < 0)
-               kfree(cmd);
+       rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb,
+                                 pn533_in_dep_link_up_complete, arg);
+
+       if (rc < 0) {
+               dev_kfree_skb(skb);
+               kfree(arg);
+       }
 
        return rc;
 }
@@ -1834,6 +1983,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
 
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
        pn533_poll_reset_mod_list(dev);
 
        if (dev->tgt_mode || dev->tgt_active_prot) {
@@ -1849,68 +2000,7 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
        return 0;
 }
 
-static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
-                               bool target)
-{
-       int payload_len = skb->len;
-       struct pn533_frame *out_frame;
-       u8 tg;
-
-       nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
-                                                               payload_len);
-
-       if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
-               /* TODO: Implement support to multi-part data exchange */
-               nfc_dev_err(&dev->interface->dev, "Data length greater than the"
-                                               " max allowed: %d",
-                                               PN533_CMD_DATAEXCH_DATA_MAXLEN);
-               return -ENOSYS;
-       }
-
-       if (target == true) {
-               switch (dev->device_type) {
-               case PN533_DEVICE_PASORI:
-                       if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
-                               skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
-                               out_frame = (struct pn533_frame *) skb->data;
-                               pn533_tx_frame_init(out_frame,
-                                                   PN533_CMD_IN_COMM_THRU);
-
-                               break;
-                       }
-
-               default:
-                       skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
-                       out_frame = (struct pn533_frame *) skb->data;
-                       pn533_tx_frame_init(out_frame,
-                                           PN533_CMD_IN_DATA_EXCHANGE);
-                       tg = 1;
-                       memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame),
-                              &tg, sizeof(u8));
-                       out_frame->datalen += sizeof(u8);
-
-                       break;
-               }
-
-       } else {
-               skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
-               out_frame = (struct pn533_frame *) skb->data;
-               pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
-       }
-
-
-       /* The data is already in the out_frame, just update the datalen */
-       out_frame->datalen += payload_len;
-
-       pn533_tx_frame_finish(out_frame);
-       skb_put(skb, PN533_FRAME_TAIL_SIZE);
-
-       return 0;
-}
-
 struct pn533_data_exchange_arg {
-       struct sk_buff *skb_resp;
-       struct sk_buff *skb_out;
        data_exchange_cb_t cb;
        void *cb_context;
 };
@@ -1920,7 +2010,7 @@ static struct sk_buff *pn533_build_response(struct pn533 *dev)
        struct sk_buff *skb, *tmp, *t;
        unsigned int skb_len = 0, tmp_len = 0;
 
-       nfc_dev_dbg(&dev->interface->dev, "%s\n", __func__);
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
        if (skb_queue_empty(&dev->resp_q))
                return NULL;
@@ -1954,46 +2044,44 @@ out:
 }
 
 static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
-                                               u8 *params, int params_len)
+                                       struct sk_buff *resp)
 {
        struct pn533_data_exchange_arg *arg = _arg;
-       struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp;
-       struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
-       int err = 0;
-       u8 status;
-       u8 cmd_ret;
+       struct sk_buff *skb;
+       int rc = 0;
+       u8 status, ret, mi;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       dev_kfree_skb(arg->skb_out);
-
-       if (params_len < 0) { /* error */
-               err = params_len;
-               goto error;
+       if (IS_ERR(resp)) {
+               rc = PTR_ERR(resp);
+               goto _error;
        }
 
-       status = params[0];
+       status = resp->data[0];
+       ret = status & PN533_CMD_RET_MASK;
+       mi = status & PN533_CMD_MI_MASK;
+
+       skb_pull(resp, sizeof(status));
 
-       cmd_ret = status & PN533_CMD_RET_MASK;
-       if (cmd_ret != PN533_CMD_RET_SUCCESS) {
-               nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when"
-                                               " exchanging data", cmd_ret);
-               err = -EIO;
+       if (ret != PN533_CMD_RET_SUCCESS) {
+               nfc_dev_err(&dev->interface->dev,
+                           "PN533 reported error %d when exchanging data",
+                           ret);
+               rc = -EIO;
                goto error;
        }
 
-       skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
-       skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
-       skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
-       skb_queue_tail(&dev->resp_q, skb_resp);
+       skb_queue_tail(&dev->resp_q, resp);
 
-       if (status & PN533_CMD_MI_MASK) {
+       if (mi) {
+               dev->cmd_complete_mi_arg = arg;
                queue_work(dev->wq, &dev->mi_work);
                return -EINPROGRESS;
        }
 
        skb = pn533_build_response(dev);
-       if (skb == NULL)
+       if (!skb)
                goto error;
 
        arg->cb(arg->cb_context, skb, 0);
@@ -2001,11 +2089,12 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
        return 0;
 
 error:
+       dev_kfree_skb(resp);
+_error:
        skb_queue_purge(&dev->resp_q);
-       dev_kfree_skb(skb_resp);
-       arg->cb(arg->cb_context, NULL, err);
+       arg->cb(arg->cb_context, NULL, rc);
        kfree(arg);
-       return 0;
+       return rc;
 }
 
 static int pn533_transceive(struct nfc_dev *nfc_dev,
@@ -2013,87 +2102,82 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
                            data_exchange_cb_t cb, void *cb_context)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-       struct pn533_frame *out_frame, *in_frame;
-       struct pn533_data_exchange_arg *arg;
-       struct sk_buff *skb_resp;
-       int skb_resp_len;
+       struct pn533_data_exchange_arg *arg = NULL;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       if (!dev->tgt_active_prot) {
-               nfc_dev_err(&dev->interface->dev, "Cannot exchange data if"
-                                               " there is no active target");
-               rc = -EINVAL;
+       if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+               /* TODO: Implement support to multi-part data exchange */
+               nfc_dev_err(&dev->interface->dev,
+                           "Data length greater than the max allowed: %d",
+                           PN533_CMD_DATAEXCH_DATA_MAXLEN);
+               rc = -ENOSYS;
                goto error;
        }
 
-       rc = pn533_build_tx_frame(dev, skb, true);
-       if (rc)
-               goto error;
-
-       skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
-                       PN533_CMD_DATAEXCH_DATA_MAXLEN +
-                       PN533_FRAME_TAIL_SIZE;
-
-       skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
-       if (!skb_resp) {
-               rc = -ENOMEM;
+       if (!dev->tgt_active_prot) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Can't exchange data if there is no active target");
+               rc = -EINVAL;
                goto error;
        }
 
-       in_frame = (struct pn533_frame *) skb_resp->data;
-       out_frame = (struct pn533_frame *) skb->data;
-
-       arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL);
+       arg = kmalloc(sizeof(*arg), GFP_KERNEL);
        if (!arg) {
                rc = -ENOMEM;
-               goto free_skb_resp;
+               goto error;
        }
 
-       arg->skb_resp = skb_resp;
-       arg->skb_out = skb;
        arg->cb = cb;
        arg->cb_context = cb_context;
 
-       rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len,
-                                       pn533_data_exchange_complete, arg,
-                                       GFP_KERNEL);
-       if (rc) {
-               nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-                                               " perform data_exchange", rc);
-               goto free_arg;
+       switch (dev->device_type) {
+       case PN533_DEVICE_PASORI:
+               if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+                       rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU,
+                                                  skb,
+                                                  pn533_data_exchange_complete,
+                                                  arg);
+
+                       break;
+               }
+       default:
+               *skb_push(skb, sizeof(u8)) =  1; /*TG*/
+
+               rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE,
+                                          skb, pn533_data_exchange_complete,
+                                          arg);
+
+               break;
        }
 
+       if (rc < 0) /* rc from send_async */
+               goto error;
+
        return 0;
 
-free_arg:
-       kfree(arg);
-free_skb_resp:
-       kfree_skb(skb_resp);
 error:
-       kfree_skb(skb);
+       kfree(arg);
+       dev_kfree_skb(skb);
        return rc;
 }
 
 static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
-                                 u8 *params, int params_len)
+                                 struct sk_buff *resp)
 {
-       struct sk_buff *skb_out = arg;
+       u8 status;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       dev_kfree_skb(skb_out);
+       if (IS_ERR(resp))
+               return PTR_ERR(resp);
 
-       if (params_len < 0) {
-               nfc_dev_err(&dev->interface->dev,
-                           "Error %d when sending data",
-                           params_len);
+       status = resp->data[0];
 
-               return params_len;
-       }
+       dev_kfree_skb(resp);
 
-       if (params_len > 0 && params[0] != 0) {
+       if (status != 0) {
                nfc_tm_deactivated(dev->nfc_dev);
 
                dev->tgt_mode = 0;
@@ -2109,30 +2193,21 @@ static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
 static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-       struct pn533_frame *out_frame;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       rc = pn533_build_tx_frame(dev, skb, false);
-       if (rc)
-               goto error;
-
-       out_frame = (struct pn533_frame *) skb->data;
-
-       rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
-                                       dev->in_maxlen, pn533_tm_send_complete,
-                                       skb, GFP_KERNEL);
-       if (rc) {
+       if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
                nfc_dev_err(&dev->interface->dev,
-                           "Error %d when trying to send data", rc);
-               goto error;
+                           "Data length greater than the max allowed: %d",
+                           PN533_CMD_DATAEXCH_DATA_MAXLEN);
+               return -ENOSYS;
        }
 
-       return 0;
-
-error:
-       kfree_skb(skb);
+       rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_DATA, skb,
+                                  pn533_tm_send_complete, NULL);
+       if (rc < 0)
+               dev_kfree_skb(skb);
 
        return rc;
 }
@@ -2140,107 +2215,123 @@ error:
 static void pn533_wq_mi_recv(struct work_struct *work)
 {
        struct pn533 *dev = container_of(work, struct pn533, mi_work);
-       struct sk_buff *skb_cmd;
-       struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg;
-       struct pn533_frame *out_frame, *in_frame;
-       struct sk_buff *skb_resp;
-       int skb_resp_len;
+
+       struct sk_buff *skb;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       /* This is a zero payload size skb */
-       skb_cmd = alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN + PN533_FRAME_TAIL_SIZE,
-                           GFP_KERNEL);
-       if (skb_cmd == NULL)
-               goto error_cmd;
-
-       skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
+       skb = pn533_alloc_skb(dev, PN533_CMD_DATAEXCH_HEAD_LEN);
+       if (!skb)
+               goto error;
 
-       rc = pn533_build_tx_frame(dev, skb_cmd, true);
-       if (rc)
-               goto error_frame;
+       switch (dev->device_type) {
+       case PN533_DEVICE_PASORI:
+               if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+                       rc = pn533_send_cmd_direct_async(dev,
+                                               PN533_CMD_IN_COMM_THRU,
+                                               skb,
+                                               pn533_data_exchange_complete,
+                                                dev->cmd_complete_mi_arg);
 
-       skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
-                       PN533_CMD_DATAEXCH_DATA_MAXLEN +
-                       PN533_FRAME_TAIL_SIZE;
-       skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL);
-       if (!skb_resp) {
-               rc = -ENOMEM;
-               goto error_frame;
-       }
+                       break;
+               }
+       default:
+               *skb_put(skb, sizeof(u8)) =  1; /*TG*/
 
-       in_frame = (struct pn533_frame *) skb_resp->data;
-       out_frame = (struct pn533_frame *) skb_cmd->data;
+               rc = pn533_send_cmd_direct_async(dev,
+                                                PN533_CMD_IN_DATA_EXCHANGE,
+                                                skb,
+                                                pn533_data_exchange_complete,
+                                                dev->cmd_complete_mi_arg);
 
-       arg->skb_resp = skb_resp;
-       arg->skb_out = skb_cmd;
+               break;
+       }
 
-       rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
-                                         skb_resp_len,
-                                         pn533_data_exchange_complete,
-                                         dev->cmd_complete_arg, GFP_KERNEL);
-       if (!rc)
+       if (rc == 0) /* success */
                return;
 
-       nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-                                               " perform data_exchange", rc);
-
-       kfree_skb(skb_resp);
+       nfc_dev_err(&dev->interface->dev,
+                   "Error %d when trying to perform data_exchange", rc);
 
-error_frame:
-       kfree_skb(skb_cmd);
+       dev_kfree_skb(skb);
+       kfree(dev->cmd_complete_arg);
 
-error_cmd:
+error:
        pn533_send_ack(dev, GFP_KERNEL);
-
-       kfree(arg);
-
        queue_work(dev->wq, &dev->cmd_work);
 }
 
 static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
                                                                u8 cfgdata_len)
 {
-       int rc;
-       u8 *params;
+       struct sk_buff *skb;
+       struct sk_buff *resp;
+
+       int skb_len;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       pn533_tx_frame_init(dev->out_frame, PN533_CMD_RF_CONFIGURATION);
+       skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */
 
-       params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
-       params[0] = cfgitem;
-       memcpy(&params[1], cfgdata, cfgdata_len);
-       dev->out_frame->datalen += (1 + cfgdata_len);
+       skb = pn533_alloc_skb(dev, skb_len);
+       if (!skb)
+               return -ENOMEM;
 
-       pn533_tx_frame_finish(dev->out_frame);
+       *skb_put(skb, sizeof(cfgitem)) = cfgitem;
+       memcpy(skb_put(skb, cfgdata_len), cfgdata, cfgdata_len);
 
-       rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-                                                               dev->in_maxlen);
+       resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb);
+       if (IS_ERR(resp))
+               return PTR_ERR(resp);
 
-       return rc;
+       dev_kfree_skb(resp);
+       return 0;
+}
+
+static int pn533_get_firmware_version(struct pn533 *dev,
+                                     struct pn533_fw_version *fv)
+{
+       struct sk_buff *skb;
+       struct sk_buff *resp;
+
+       skb = pn533_alloc_skb(dev, 0);
+       if (!skb)
+               return -ENOMEM;
+
+       resp = pn533_send_cmd_sync(dev, PN533_CMD_GET_FIRMWARE_VERSION, skb);
+       if (IS_ERR(resp))
+               return PTR_ERR(resp);
+
+       fv->ic = resp->data[0];
+       fv->ver = resp->data[1];
+       fv->rev = resp->data[2];
+       fv->support = resp->data[3];
+
+       dev_kfree_skb(resp);
+       return 0;
 }
 
 static int pn533_fw_reset(struct pn533 *dev)
 {
-       int rc;
-       u8 *params;
+       struct sk_buff *skb;
+       struct sk_buff *resp;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       pn533_tx_frame_init(dev->out_frame, 0x18);
+       skb = pn533_alloc_skb(dev, sizeof(u8));
+       if (!skb)
+               return -ENOMEM;
 
-       params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
-       params[0] = 0x1;
-       dev->out_frame->datalen += 1;
+       *skb_put(skb, sizeof(u8)) = 0x1;
 
-       pn533_tx_frame_finish(dev->out_frame);
+       resp = pn533_send_cmd_sync(dev, 0x18, skb);
+       if (IS_ERR(resp))
+               return PTR_ERR(resp);
 
-       rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-                                      dev->in_maxlen);
+       dev_kfree_skb(resp);
 
-       return rc;
+       return 0;
 }
 
 static struct nfc_ops pn533_nfc_ops = {
@@ -2337,7 +2428,7 @@ static int pn533_setup(struct pn533 *dev)
 static int pn533_probe(struct usb_interface *interface,
                        const struct usb_device_id *id)
 {
-       struct pn533_fw_version *fw_ver;
+       struct pn533_fw_version fw_ver;
        struct pn533 *dev;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
@@ -2359,41 +2450,32 @@ static int pn533_probe(struct usb_interface *interface,
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
 
-               if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
-                       dev->in_maxlen = le16_to_cpu(endpoint->wMaxPacketSize);
+               if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint))
                        in_endpoint = endpoint->bEndpointAddress;
-               }
 
-               if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) {
-                       dev->out_maxlen =
-                               le16_to_cpu(endpoint->wMaxPacketSize);
+               if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint))
                        out_endpoint = endpoint->bEndpointAddress;
-               }
        }
 
        if (!in_endpoint || !out_endpoint) {
-               nfc_dev_err(&interface->dev, "Could not find bulk-in or"
-                                                       " bulk-out endpoint");
+               nfc_dev_err(&interface->dev,
+                           "Could not find bulk-in or bulk-out endpoint");
                rc = -ENODEV;
                goto error;
        }
 
-       dev->in_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
        dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);
-       dev->out_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
        dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
 
-       if (!dev->in_frame || !dev->out_frame ||
-               !dev->in_urb || !dev->out_urb)
+       if (!dev->in_urb || !dev->out_urb)
                goto error;
 
        usb_fill_bulk_urb(dev->in_urb, dev->udev,
-                       usb_rcvbulkpipe(dev->udev, in_endpoint),
-                       NULL, 0, NULL, dev);
+                         usb_rcvbulkpipe(dev->udev, in_endpoint),
+                         NULL, 0, NULL, dev);
        usb_fill_bulk_urb(dev->out_urb, dev->udev,
-                       usb_sndbulkpipe(dev->udev, out_endpoint),
-                       NULL, 0,
-                       pn533_send_complete, dev);
+                         usb_sndbulkpipe(dev->udev, out_endpoint),
+                         NULL, 0, pn533_send_complete, dev);
 
        INIT_WORK(&dev->cmd_work, pn533_wq_cmd);
        INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete);
@@ -2414,18 +2496,7 @@ static int pn533_probe(struct usb_interface *interface,
 
        usb_set_intfdata(interface, dev);
 
-       pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION);
-       pn533_tx_frame_finish(dev->out_frame);
-
-       rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-                                                               dev->in_maxlen);
-       if (rc)
-               goto destroy_wq;
-
-       fw_ver = (struct pn533_fw_version *)
-                               PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
-       nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now"
-                                       " attached", fw_ver->ver, fw_ver->rev);
+       dev->ops = &pn533_std_frame_ops;
 
        dev->device_type = id->driver_info;
        switch (dev->device_type) {
@@ -2444,9 +2515,21 @@ static int pn533_probe(struct usb_interface *interface,
                goto destroy_wq;
        }
 
+       memset(&fw_ver, 0, sizeof(fw_ver));
+       rc = pn533_get_firmware_version(dev, &fw_ver);
+       if (rc < 0)
+               goto destroy_wq;
+
+       nfc_dev_info(&dev->interface->dev,
+                    "NXP PN533 firmware ver %d.%d now attached",
+                    fw_ver.ver, fw_ver.rev);
+
+
        dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
+                                          NFC_SE_NONE,
+                                          dev->ops->tx_header_len +
                                           PN533_CMD_DATAEXCH_HEAD_LEN,
-                                          PN533_FRAME_TAIL_SIZE);
+                                          dev->ops->tx_tail_len);
        if (!dev->nfc_dev)
                goto destroy_wq;
 
@@ -2472,9 +2555,7 @@ free_nfc_dev:
 destroy_wq:
        destroy_workqueue(dev->wq);
 error:
-       kfree(dev->in_frame);
        usb_free_urb(dev->in_urb);
-       kfree(dev->out_frame);
        usb_free_urb(dev->out_urb);
        kfree(dev);
        return rc;
@@ -2505,9 +2586,7 @@ static void pn533_disconnect(struct usb_interface *interface)
                kfree(cmd);
        }
 
-       kfree(dev->in_frame);
        usb_free_urb(dev->in_urb);
-       kfree(dev->out_frame);
        usb_free_urb(dev->out_urb);
        kfree(dev);
 
diff --git a/drivers/nfc/pn544/Kconfig b/drivers/nfc/pn544/Kconfig
new file mode 100644 (file)
index 0000000..c277790
--- /dev/null
@@ -0,0 +1,23 @@
+config NFC_PN544
+       tristate "NXP PN544 NFC driver"
+       depends on NFC_HCI
+       select CRC_CCITT
+       default n
+       ---help---
+         NXP PN544 core driver.
+         This is a driver based on the HCI NFC kernel layers and
+         will thus not work with NXP libnfc library.
+
+         To compile this driver as a module, choose m here. The module will
+         be called pn544.
+         Say N if unsure.
+
+config NFC_PN544_I2C
+       tristate "NFC PN544 i2c support"
+       depends on NFC_PN544 && I2C && NFC_SHDLC
+       ---help---
+         This module adds support for the NXP pn544 i2c interface.
+         Select this if your platform is using the i2c bus.
+
+         If you choose to build a module, it'll be called pn544_i2c.
+         Say N if unsure.
\ No newline at end of file
index 725733881eb3d04074629b5b9e8acd13e24b375f..ac076793687d582d4ec6068fd444f55dc84c15c8 100644 (file)
@@ -2,6 +2,7 @@
 # Makefile for PN544 HCI based NFC driver
 #
 
-obj-$(CONFIG_PN544_HCI_NFC)    += pn544_i2c.o
+pn544_i2c-objs  = i2c.o
 
-pn544_i2c-y            := pn544.o i2c.o
+obj-$(CONFIG_NFC_PN544)     += pn544.o
+obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
index 2a9c8d93d2e8a302e8db87b91160e7fdd301a77d..8cf64c19f0229c97952ecd9f9fb689b29c6c3240 100644 (file)
@@ -376,12 +376,12 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       phy = kzalloc(sizeof(struct pn544_i2c_phy), GFP_KERNEL);
+       phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy),
+                          GFP_KERNEL);
        if (!phy) {
                dev_err(&client->dev,
                        "Cannot allocate memory for pn544 i2c phy.\n");
-               r = -ENOMEM;
-               goto err_phy_alloc;
+               return -ENOMEM;
        }
 
        phy->i2c_dev = client;
@@ -390,20 +390,18 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
        pdata = client->dev.platform_data;
        if (pdata == NULL) {
                dev_err(&client->dev, "No platform data\n");
-               r = -EINVAL;
-               goto err_pdata;
+               return -EINVAL;
        }
 
        if (pdata->request_resources == NULL) {
                dev_err(&client->dev, "request_resources() missing\n");
-               r = -EINVAL;
-               goto err_pdata;
+               return -EINVAL;
        }
 
        r = pdata->request_resources(client);
        if (r) {
                dev_err(&client->dev, "Cannot get platform resources\n");
-               goto err_pdata;
+               return r;
        }
 
        phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
@@ -435,10 +433,6 @@ err_rti:
        if (pdata->free_resources != NULL)
                pdata->free_resources();
 
-err_pdata:
-       kfree(phy);
-
-err_phy_alloc:
        return r;
 }
 
@@ -458,8 +452,6 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
        if (pdata->free_resources)
                pdata->free_resources();
 
-       kfree(phy);
-
        return 0;
 }
 
@@ -472,29 +464,7 @@ static struct i2c_driver pn544_hci_i2c_driver = {
        .remove = pn544_hci_i2c_remove,
 };
 
-static int __init pn544_hci_i2c_init(void)
-{
-       int r;
-
-       pr_debug(DRIVER_DESC ": %s\n", __func__);
-
-       r = i2c_add_driver(&pn544_hci_i2c_driver);
-       if (r) {
-               pr_err(PN544_HCI_I2C_DRIVER_NAME
-                      ": driver registration failed\n");
-               return r;
-       }
-
-       return 0;
-}
-
-static void __exit pn544_hci_i2c_exit(void)
-{
-       i2c_del_driver(&pn544_hci_i2c_driver);
-}
-
-module_init(pn544_hci_i2c_init);
-module_exit(pn544_hci_i2c_exit);
+module_i2c_driver(pn544_hci_i2c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRIVER_DESC);
index cc666de3b8e5a56b58ac984ff1f5ab890048c2e9..9c5f16e7baefa40970f7d3274aaff53fcd2f8c9a 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include <linux/nfc.h>
 #include <net/nfc/hci.h>
@@ -675,11 +676,17 @@ static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
 
 static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
 {
+       int r;
+
        /* Set default false for multiple information chaining */
        *skb_push(skb, 1) = 0;
 
-       return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
-                               PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
+       r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
+                              PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
+
+       kfree_skb(skb);
+
+       return r;
 }
 
 static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
@@ -714,35 +721,40 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
        return 0;
 }
 
-static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
-                                       u8 event, struct sk_buff *skb)
+/*
+ * Returns:
+ * <= 0: driver handled the event, skb consumed
+ *    1: driver does not handle the event, please do standard processing
+ */
+static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+                                   struct sk_buff *skb)
 {
        struct sk_buff *rgb_skb = NULL;
-       int r = 0;
+       int r;
 
        pr_debug("hci event %d", event);
        switch (event) {
        case PN544_HCI_EVT_ACTIVATED:
-               if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
-                       nfc_hci_target_discovered(hdev, gate);
-               else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
+               if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
+                       r = nfc_hci_target_discovered(hdev, gate);
+               else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
                        r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
-                                               &rgb_skb);
-
+                                             &rgb_skb);
                        if (r < 0)
                                goto exit;
 
-                       nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
-                                       NFC_COMM_PASSIVE, rgb_skb->data,
-                                       rgb_skb->len);
+                       r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+                                            NFC_COMM_PASSIVE, rgb_skb->data,
+                                            rgb_skb->len);
 
                        kfree_skb(rgb_skb);
+               } else {
+                       r = -EINVAL;
                }
-
                break;
        case PN544_HCI_EVT_DEACTIVATED:
-               nfc_hci_send_event(hdev, gate,
-                       NFC_HCI_EVT_END_OPERATION, NULL, 0);
+               r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
+                                      NULL, 0);
                break;
        case PN544_HCI_EVT_RCV_DATA:
                if (skb->len < 2) {
@@ -757,15 +769,15 @@ static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
                }
 
                skb_pull(skb, 2);
-               nfc_tm_data_received(hdev->ndev, skb);
-
-               return;
+               return nfc_tm_data_received(hdev->ndev, skb);
        default:
-               break;
+               return 1;
        }
 
 exit:
        kfree_skb(skb);
+
+       return r;
 }
 
 static struct nfc_hci_ops pn544_hci_ops = {
@@ -789,7 +801,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
                    struct nfc_hci_dev **hdev)
 {
        struct pn544_hci_info *info;
-       u32 protocols;
+       u32 protocols, se;
        struct nfc_hci_init_data init_data;
        int r;
 
@@ -822,8 +834,10 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
                    NFC_PROTO_ISO14443_B_MASK |
                    NFC_PROTO_NFC_DEP_MASK;
 
-       info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
-                                            protocols, llc_name,
+       se = NFC_SE_UICC | NFC_SE_EMBEDDED;
+
+       info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
+                                            protocols, se, llc_name,
                                             phy_headroom + PN544_CMDS_HEADROOM,
                                             phy_tailroom, phy_payload);
        if (!info->hdev) {
@@ -851,6 +865,7 @@ err_alloc_hdev:
 err_info_alloc:
        return r;
 }
+EXPORT_SYMBOL(pn544_hci_probe);
 
 void pn544_hci_remove(struct nfc_hci_dev *hdev)
 {
@@ -860,3 +875,7 @@ void pn544_hci_remove(struct nfc_hci_dev *hdev)
        nfc_hci_free_device(hdev);
        kfree(info);
 }
+EXPORT_SYMBOL(pn544_hci_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
index 83ca06f4312b8214e721dd21065f47b79032ab26..e3a8b22ef9dd04fcdefb80e34b4cfb1a92fb1382 100644 (file)
@@ -157,7 +157,7 @@ struct phy_device *of_phy_connect(struct net_device *dev,
        if (!phy)
                return NULL;
 
-       return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
+       return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy;
 }
 EXPORT_SYMBOL(of_phy_connect);
 
@@ -194,7 +194,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
 
        sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
 
-       phy = phy_connect(dev, bus_id, hndlr, 0, iface);
+       phy = phy_connect(dev, bus_id, hndlr, iface);
        return IS_ERR(phy) ? NULL : phy;
 }
 EXPORT_SYMBOL(of_phy_connect_fixed_link);
index dfda748c40004c368b02657de932dd5334241b5e..8b3f5599180595df9cd28422fe1dec2ddc2183aa 100644 (file)
@@ -74,8 +74,8 @@ config QETH
        depends on CCW && NETDEVICES && IP_MULTICAST && QDIO
        help
          This driver supports the IBM System z OSA Express adapters
-         in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN
-         interfaces in QDIO and HIPER mode.
+         in QDIO mode (all media types), HiperSockets interfaces and z/VM
+         virtual NICs for Guest LAN and VSWITCH.
        
          For details please refer to the documentation provided by IBM at
          <http://www.ibm.com/developerworks/linux/linux390>
index 480fbeab0256ab3406feffd0dd93a2b70dc666c8..d690b33846ccc211dfde01e950b65990a5082efa 100644 (file)
@@ -678,6 +678,7 @@ struct qeth_card_options {
        int performance_stats;
        int rx_sg_cb;
        enum qeth_ipa_isolation_modes isolation;
+       enum qeth_ipa_isolation_modes prev_isolation;
        int sniffer;
        enum qeth_cq cq;
        char hsuid[9];
@@ -789,6 +790,7 @@ struct qeth_card {
        struct qeth_rx rx;
        struct delayed_work buffer_reclaim_work;
        int reclaim_index;
+       struct work_struct close_dev_work;
 };
 
 struct qeth_card_list_struct {
@@ -909,9 +911,6 @@ struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *);
 int qeth_mdio_read(struct net_device *, int, int);
 int qeth_snmp_command(struct qeth_card *, char __user *);
 int qeth_query_oat_command(struct qeth_card *, char __user *);
-struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32);
-int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *,
-                                       unsigned long);
 int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
        int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
        void *reply_param);
@@ -928,12 +927,13 @@ void qeth_core_get_strings(struct net_device *, u32, u8 *);
 void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
 void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
 int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
-int qeth_set_access_ctrl_online(struct qeth_card *card);
+int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback);
 int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
 int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
 int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
 int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot);
 void qeth_trace_features(struct qeth_card *);
+void qeth_close_dev(struct qeth_card *);
 
 /* exports for OSN */
 int qeth_osn_assist(struct net_device *, void *, int);
index 638a57f4d8a11cc1ad040914f7991f2a780fefd9..0d8cdff818139e8ee267f57df08c78494c1592d0 100644 (file)
@@ -68,6 +68,27 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
                enum qeth_qdio_buffer_states newbufstate);
 static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
 
+static struct workqueue_struct *qeth_wq;
+
+static void qeth_close_dev_handler(struct work_struct *work)
+{
+       struct qeth_card *card;
+
+       card = container_of(work, struct qeth_card, close_dev_work);
+       QETH_CARD_TEXT(card, 2, "cldevhdl");
+       rtnl_lock();
+       dev_close(card->dev);
+       rtnl_unlock();
+       ccwgroup_set_offline(card->gdev);
+}
+
+void qeth_close_dev(struct qeth_card *card)
+{
+       QETH_CARD_TEXT(card, 2, "cldevsubm");
+       queue_work(qeth_wq, &card->close_dev_work);
+}
+EXPORT_SYMBOL_GPL(qeth_close_dev);
+
 static inline const char *qeth_get_cardname(struct qeth_card *card)
 {
        if (card->info.guestlan) {
@@ -542,11 +563,23 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
                } else {
                        switch (cmd->hdr.command) {
                        case IPA_CMD_STOPLAN:
-                               dev_warn(&card->gdev->dev,
+                               if (cmd->hdr.return_code ==
+                                               IPA_RC_VEPA_TO_VEB_TRANSITION) {
+                                       dev_err(&card->gdev->dev,
+                                          "Interface %s is down because the "
+                                          "adjacent port is no longer in "
+                                          "reflective relay mode\n",
+                                          QETH_CARD_IFNAME(card));
+                                       qeth_close_dev(card);
+                               } else {
+                                       dev_warn(&card->gdev->dev,
                                           "The link for interface %s on CHPID"
                                           " 0x%X failed\n",
                                           QETH_CARD_IFNAME(card),
                                           card->info.chpid);
+                                       qeth_issue_ipa_msg(cmd,
+                                               cmd->hdr.return_code, card);
+                               }
                                card->lan_online = 0;
                                if (card->dev && netif_carrier_ok(card->dev))
                                        netif_carrier_off(card->dev);
@@ -1416,6 +1449,7 @@ static int qeth_setup_card(struct qeth_card *card)
        /* init QDIO stuff */
        qeth_init_qdio_info(card);
        INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work);
+       INIT_WORK(&card->close_dev_work, qeth_close_dev_handler);
        return 0;
 }
 
@@ -2868,7 +2902,7 @@ int qeth_send_startlan(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_send_startlan);
 
-int qeth_default_setadapterparms_cb(struct qeth_card *card,
+static int qeth_default_setadapterparms_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
 {
        struct qeth_ipa_cmd *cmd;
@@ -2881,7 +2915,6 @@ int qeth_default_setadapterparms_cb(struct qeth_card *card,
                        cmd->data.setadapterparms.hdr.return_code;
        return 0;
 }
-EXPORT_SYMBOL_GPL(qeth_default_setadapterparms_cb);
 
 static int qeth_query_setadapterparms_cb(struct qeth_card *card,
                struct qeth_reply *reply, unsigned long data)
@@ -2901,7 +2934,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
        return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
 }
 
-struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
+static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
                __u32 command, __u32 cmdlen)
 {
        struct qeth_cmd_buffer *iob;
@@ -2917,7 +2950,6 @@ struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
 
        return iob;
 }
-EXPORT_SYMBOL_GPL(qeth_get_adapter_cmd);
 
 int qeth_query_setadapterparms(struct qeth_card *card)
 {
@@ -4059,6 +4091,7 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
 {
        struct qeth_ipa_cmd *cmd;
        struct qeth_set_access_ctrl *access_ctrl_req;
+       int fallback = *(int *)reply->param;
 
        QETH_CARD_TEXT(card, 4, "setaccb");
 
@@ -4068,12 +4101,14 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
        QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
        QETH_DBF_TEXT_(SETUP, 2, "rc=%d",
                cmd->data.setadapterparms.hdr.return_code);
+       if (cmd->data.setadapterparms.hdr.return_code !=
+                                               SET_ACCESS_CTRL_RC_SUCCESS)
+               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
+                               card->gdev->dev.kobj.name,
+                               access_ctrl_req->subcmd_code,
+                               cmd->data.setadapterparms.hdr.return_code);
        switch (cmd->data.setadapterparms.hdr.return_code) {
        case SET_ACCESS_CTRL_RC_SUCCESS:
-       case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
-       case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
-       {
-               card->options.isolation = access_ctrl_req->subcmd_code;
                if (card->options.isolation == ISOLATION_MODE_NONE) {
                        dev_info(&card->gdev->dev,
                            "QDIO data connection isolation is deactivated\n");
@@ -4081,72 +4116,64 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
                        dev_info(&card->gdev->dev,
                            "QDIO data connection isolation is activated\n");
                }
-               QETH_DBF_MESSAGE(3, "OK:SET_ACCESS_CTRL(%s, %d)==%d\n",
-                       card->gdev->dev.kobj.name,
-                       access_ctrl_req->subcmd_code,
-                       cmd->data.setadapterparms.hdr.return_code);
                break;
-       }
+       case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
+               QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already "
+                               "deactivated\n", dev_name(&card->gdev->dev));
+               if (fallback)
+                       card->options.isolation = card->options.prev_isolation;
+               break;
+       case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
+               QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already"
+                               " activated\n", dev_name(&card->gdev->dev));
+               if (fallback)
+                       card->options.isolation = card->options.prev_isolation;
+               break;
        case SET_ACCESS_CTRL_RC_NOT_SUPPORTED:
-       {
-               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
-                       card->gdev->dev.kobj.name,
-                       access_ctrl_req->subcmd_code,
-                       cmd->data.setadapterparms.hdr.return_code);
                dev_err(&card->gdev->dev, "Adapter does not "
                        "support QDIO data connection isolation\n");
-
-               /* ensure isolation mode is "none" */
-               card->options.isolation = ISOLATION_MODE_NONE;
                break;
-       }
        case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER:
-       {
-               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
-                       card->gdev->dev.kobj.name,
-                       access_ctrl_req->subcmd_code,
-                       cmd->data.setadapterparms.hdr.return_code);
                dev_err(&card->gdev->dev,
                        "Adapter is dedicated. "
                        "QDIO data connection isolation not supported\n");
-
-               /* ensure isolation mode is "none" */
-               card->options.isolation = ISOLATION_MODE_NONE;
+               if (fallback)
+                       card->options.isolation = card->options.prev_isolation;
                break;
-       }
        case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF:
-       {
-               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
-                       card->gdev->dev.kobj.name,
-                       access_ctrl_req->subcmd_code,
-                       cmd->data.setadapterparms.hdr.return_code);
                dev_err(&card->gdev->dev,
                        "TSO does not permit QDIO data connection isolation\n");
-
-               /* ensure isolation mode is "none" */
-               card->options.isolation = ISOLATION_MODE_NONE;
+               if (fallback)
+                       card->options.isolation = card->options.prev_isolation;
+               break;
+       case SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED:
+               dev_err(&card->gdev->dev, "The adjacent switch port does not "
+                       "support reflective relay mode\n");
+               if (fallback)
+                       card->options.isolation = card->options.prev_isolation;
+               break;
+       case SET_ACCESS_CTRL_RC_REFLREL_FAILED:
+               dev_err(&card->gdev->dev, "The reflective relay mode cannot be "
+                                       "enabled at the adjacent switch port");
+               if (fallback)
+                       card->options.isolation = card->options.prev_isolation;
+               break;
+       case SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED:
+               dev_warn(&card->gdev->dev, "Turning off reflective relay mode "
+                                       "at the adjacent switch failed\n");
                break;
-       }
        default:
-       {
                /* this should never happen */
-               QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d"
-                       "==UNKNOWN\n",
-                       card->gdev->dev.kobj.name,
-                       access_ctrl_req->subcmd_code,
-                       cmd->data.setadapterparms.hdr.return_code);
-
-               /* ensure isolation mode is "none" */
-               card->options.isolation = ISOLATION_MODE_NONE;
+               if (fallback)
+                       card->options.isolation = card->options.prev_isolation;
                break;
        }
-       }
        qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
        return 0;
 }
 
 static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
-               enum qeth_ipa_isolation_modes isolation)
+               enum qeth_ipa_isolation_modes isolation, int fallback)
 {
        int rc;
        struct qeth_cmd_buffer *iob;
@@ -4166,12 +4193,12 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
        access_ctrl_req->subcmd_code = isolation;
 
        rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb,
-                              NULL);
+                              &fallback);
        QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc);
        return rc;
 }
 
-int qeth_set_access_ctrl_online(struct qeth_card *card)
+int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback)
 {
        int rc = 0;
 
@@ -4181,12 +4208,13 @@ int qeth_set_access_ctrl_online(struct qeth_card *card)
             card->info.type == QETH_CARD_TYPE_OSX) &&
             qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
                rc = qeth_setadpparms_set_access_ctrl(card,
-                       card->options.isolation);
+                       card->options.isolation, fallback);
                if (rc) {
                        QETH_DBF_MESSAGE(3,
                                "IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n",
                                card->gdev->dev.kobj.name,
                                rc);
+                       rc = -EOPNOTSUPP;
                }
        } else if (card->options.isolation != ISOLATION_MODE_NONE) {
                card->options.isolation = ISOLATION_MODE_NONE;
@@ -4672,7 +4700,7 @@ static int qeth_qdio_establish(struct qeth_card *card)
        init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
        init_data.output_sbal_state_array = card->qdio.out_bufstates;
        init_data.scan_threshold =
-               (card->info.type == QETH_CARD_TYPE_IQD) ? 8 : 32;
+               (card->info.type == QETH_CARD_TYPE_IQD) ? 1 : 32;
 
        if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
                QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) {
@@ -4765,14 +4793,14 @@ static struct ccw_driver qeth_ccw_driver = {
 
 int qeth_core_hardsetup_card(struct qeth_card *card)
 {
-       int retries = 0;
+       int retries = 3;
        int rc;
 
        QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
        atomic_set(&card->force_alloc_skb, 0);
        qeth_update_from_chp_desc(card);
 retry:
-       if (retries)
+       if (retries < 3)
                QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
                        dev_name(&card->gdev->dev));
        ccw_device_set_offline(CARD_DDEV(card));
@@ -4794,7 +4822,7 @@ retriable:
                return rc;
        } else if (rc) {
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
-               if (++retries > 3)
+               if (--retries < 0)
                        goto out;
                else
                        goto retry;
@@ -5094,13 +5122,81 @@ static const struct device_type qeth_osn_devtype = {
        .groups = qeth_osn_attr_groups,
 };
 
+#define DBF_NAME_LEN   20
+
+struct qeth_dbf_entry {
+       char dbf_name[DBF_NAME_LEN];
+       debug_info_t *dbf_info;
+       struct list_head dbf_list;
+};
+
+static LIST_HEAD(qeth_dbf_list);
+static DEFINE_MUTEX(qeth_dbf_list_mutex);
+
+static debug_info_t *qeth_get_dbf_entry(char *name)
+{
+       struct qeth_dbf_entry *entry;
+       debug_info_t *rc = NULL;
+
+       mutex_lock(&qeth_dbf_list_mutex);
+       list_for_each_entry(entry, &qeth_dbf_list, dbf_list) {
+               if (strcmp(entry->dbf_name, name) == 0) {
+                       rc = entry->dbf_info;
+                       break;
+               }
+       }
+       mutex_unlock(&qeth_dbf_list_mutex);
+       return rc;
+}
+
+static int qeth_add_dbf_entry(struct qeth_card *card, char *name)
+{
+       struct qeth_dbf_entry *new_entry;
+
+       card->debug = debug_register(name, 2, 1, 8);
+       if (!card->debug) {
+               QETH_DBF_TEXT_(SETUP, 2, "%s", "qcdbf");
+               goto err;
+       }
+       if (debug_register_view(card->debug, &debug_hex_ascii_view))
+               goto err_dbg;
+       new_entry = kzalloc(sizeof(struct qeth_dbf_entry), GFP_KERNEL);
+       if (!new_entry)
+               goto err_dbg;
+       strncpy(new_entry->dbf_name, name, DBF_NAME_LEN);
+       new_entry->dbf_info = card->debug;
+       mutex_lock(&qeth_dbf_list_mutex);
+       list_add(&new_entry->dbf_list, &qeth_dbf_list);
+       mutex_unlock(&qeth_dbf_list_mutex);
+
+       return 0;
+
+err_dbg:
+       debug_unregister(card->debug);
+err:
+       return -ENOMEM;
+}
+
+static void qeth_clear_dbf_list(void)
+{
+       struct qeth_dbf_entry *entry, *tmp;
+
+       mutex_lock(&qeth_dbf_list_mutex);
+       list_for_each_entry_safe(entry, tmp, &qeth_dbf_list, dbf_list) {
+               list_del(&entry->dbf_list);
+               debug_unregister(entry->dbf_info);
+               kfree(entry);
+       }
+       mutex_unlock(&qeth_dbf_list_mutex);
+}
+
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card;
        struct device *dev;
        int rc;
        unsigned long flags;
-       char dbf_name[20];
+       char dbf_name[DBF_NAME_LEN];
 
        QETH_DBF_TEXT(SETUP, 2, "probedev");
 
@@ -5119,13 +5215,12 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 
        snprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s",
                dev_name(&gdev->dev));
-       card->debug = debug_register(dbf_name, 2, 1, 8);
+       card->debug = qeth_get_dbf_entry(dbf_name);
        if (!card->debug) {
-               QETH_DBF_TEXT_(SETUP, 2, "%s", "qcdbf");
-               rc = -ENOMEM;
-               goto err_card;
+               rc = qeth_add_dbf_entry(card, dbf_name);
+               if (rc)
+                       goto err_card;
        }
-       debug_register_view(card->debug, &debug_hex_ascii_view);
 
        card->read.ccwdev  = gdev->cdev[0];
        card->write.ccwdev = gdev->cdev[1];
@@ -5139,12 +5234,12 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
        rc = qeth_determine_card_type(card);
        if (rc) {
                QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-               goto err_dbf;
+               goto err_card;
        }
        rc = qeth_setup_card(card);
        if (rc) {
                QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
-               goto err_dbf;
+               goto err_card;
        }
 
        if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -5157,7 +5252,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
        case QETH_CARD_TYPE_OSM:
                rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
                if (rc)
-                       goto err_dbf;
+                       goto err_card;
                rc = card->discipline->setup(card->gdev);
                if (rc)
                        goto err_disc;
@@ -5176,8 +5271,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 
 err_disc:
        qeth_core_free_discipline(card);
-err_dbf:
-       debug_unregister(card->debug);
 err_card:
        qeth_core_free_card(card);
 err_dev:
@@ -5197,7 +5290,6 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
                qeth_core_free_discipline(card);
        }
 
-       debug_unregister(card->debug);
        write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
        list_del(&card->list);
        write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
@@ -5444,17 +5536,14 @@ void qeth_core_get_drvinfo(struct net_device *dev,
                struct ethtool_drvinfo *info)
 {
        struct qeth_card *card = dev->ml_priv;
-       if (card->options.layer2)
-               strcpy(info->driver, "qeth_l2");
-       else
-               strcpy(info->driver, "qeth_l3");
 
-       strcpy(info->version, "1.0");
-       strcpy(info->fw_version, card->info.mcl_level);
-       sprintf(info->bus_info, "%s/%s/%s",
-                       CARD_RDEV_ID(card),
-                       CARD_WDEV_ID(card),
-                       CARD_DDEV_ID(card));
+       strlcpy(info->driver, card->options.layer2 ? "qeth_l2" : "qeth_l3",
+               sizeof(info->driver));
+       strlcpy(info->version, "1.0", sizeof(info->version));
+       strlcpy(info->fw_version, card->info.mcl_level,
+               sizeof(info->fw_version));
+       snprintf(info->bus_info, sizeof(info->bus_info), "%s/%s/%s",
+                CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
 }
 EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo);
 
@@ -5554,9 +5643,12 @@ static int __init qeth_core_init(void)
 
        pr_info("loading core functions\n");
        INIT_LIST_HEAD(&qeth_core_card_list.list);
+       INIT_LIST_HEAD(&qeth_dbf_list);
        rwlock_init(&qeth_core_card_list.rwlock);
        mutex_init(&qeth_mod_mutex);
 
+       qeth_wq = create_singlethread_workqueue("qeth_wq");
+
        rc = qeth_register_dbf_views();
        if (rc)
                goto out_err;
@@ -5603,6 +5695,8 @@ out_err:
 
 static void __exit qeth_core_exit(void)
 {
+       qeth_clear_dbf_list();
+       destroy_workqueue(qeth_wq);
        ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
        ccw_driver_unregister(&qeth_ccw_driver);
        kmem_cache_destroy(qeth_qdio_outbuf_cache);
index 5cebfddb86bdfbb40b2a0cfa6f212e5d0656cf95..06c55780005e5316769811b8f8bdd7a08745b360 100644 (file)
@@ -204,6 +204,7 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
        {IPA_RC_INVALID_SETRTG_INDICATOR, "Invalid SETRTG indicator"},
        {IPA_RC_MC_ADDR_ALREADY_DEFINED, "Multicast address already defined"},
        {IPA_RC_LAN_OFFLINE,            "STRTLAN_LAN_DISABLED - LAN offline"},
+       {IPA_RC_VEPA_TO_VEB_TRANSITION, "Adj. switch disabled port mode RR"},
        {IPA_RC_INVALID_IP_VERSION2,    "Invalid IP version"},
        {IPA_RC_ENOMEM,                 "Memory problem"},
        {IPA_RC_FFFF,                   "Unknown Error"}
index 3690bbf2cb3cf3699abadeb4f2aa0703e11c2ce2..07085d55f9a1d2c705dbdbdbdcdd2a4270ecac03 100644 (file)
@@ -177,6 +177,7 @@ enum qeth_ipa_return_codes {
        IPA_RC_INVALID_SETRTG_INDICATOR = 0xe012,
        IPA_RC_MC_ADDR_ALREADY_DEFINED  = 0xe013,
        IPA_RC_LAN_OFFLINE              = 0xe080,
+       IPA_RC_VEPA_TO_VEB_TRANSITION   = 0xe090,
        IPA_RC_INVALID_IP_VERSION2      = 0xf001,
        IPA_RC_ENOMEM                   = 0xfffe,
        IPA_RC_FFFF                     = 0xffff
@@ -269,6 +270,9 @@ enum qeth_ipa_set_access_mode_rc {
        SET_ACCESS_CTRL_RC_ALREADY_ISOLATED     = 0x0010,
        SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER  = 0x0014,
        SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF  = 0x0018,
+       SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED  = 0x0022,
+       SET_ACCESS_CTRL_RC_REFLREL_FAILED       = 0x0024,
+       SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED = 0x0028,
 };
 
 
@@ -386,6 +390,7 @@ struct qeth_snmp_ureq {
 /* SET_ACCESS_CONTROL: same format for request and reply */
 struct qeth_set_access_ctrl {
        __u32 subcmd_code;
+       __u8 reserved[8];
 } __attribute__((packed));
 
 struct qeth_query_oat {
index 9655dc0ea0ec7187c65de00eb30399bf13ffe1fb..425c0ecf1f3b9fd2ae3c2c55f61b1ad10f08c028 100644 (file)
@@ -513,10 +513,11 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
        rc = count;
 
        /* defer IP assist if device is offline (until discipline->set_online)*/
+       card->options.prev_isolation = card->options.isolation;
        card->options.isolation = isolation;
        if (card->state == CARD_STATE_SOFTSETUP ||
            card->state == CARD_STATE_UP) {
-               int ipa_rc = qeth_set_access_ctrl_online(card);
+               int ipa_rc = qeth_set_access_ctrl_online(card, 1);
                if (ipa_rc != 0)
                        rc = ipa_rc;
        }
index 73195553f84b168442918a0c6697d9ef090999c2..d690166efeaffbd4d47f1d39d3111af232876e66 100644 (file)
@@ -1025,9 +1025,14 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
 
 contin:
        if ((card->info.type == QETH_CARD_TYPE_OSD) ||
-           (card->info.type == QETH_CARD_TYPE_OSX))
+           (card->info.type == QETH_CARD_TYPE_OSX)) {
                /* configure isolation level */
-               qeth_set_access_ctrl_online(card);
+               rc = qeth_set_access_ctrl_online(card, 0);
+               if (rc) {
+                       rc = -ENODEV;
+                       goto out_remove;
+               }
+       }
 
        if (card->info.type != QETH_CARD_TYPE_OSN &&
            card->info.type != QETH_CARD_TYPE_OSM)
@@ -1144,12 +1149,9 @@ static int qeth_l2_recover(void *ptr)
                dev_info(&card->gdev->dev,
                        "Device successfully recovered!\n");
        else {
-               if (rtnl_trylock()) {
-                       dev_close(card->dev);
-                       rtnl_unlock();
-                       dev_warn(&card->gdev->dev, "The qeth device driver "
+               qeth_close_dev(card);
+               dev_warn(&card->gdev->dev, "The qeth device driver "
                                "failed to recover an error on the device\n");
-               }
        }
        qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
        qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
index 6e5eef01e66784b4eaa3e9357d81c7e89b96e47e..091ca0efa1c539e0ca27f57f55a00cb543bfc304 100644 (file)
@@ -1449,7 +1449,8 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)
 {
        QETH_CARD_TEXT(card, 3, "strtipas");
 
-       qeth_set_access_ctrl_online(card);      /* go on*/
+       if (qeth_set_access_ctrl_online(card, 0))
+               return -EIO;
        qeth_l3_start_ipa_arp_processing(card); /* go on*/
        qeth_l3_start_ipa_ip_fragmentation(card);       /* go on*/
        qeth_l3_start_ipa_source_mac(card);     /* go on*/
@@ -1640,6 +1641,7 @@ static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev)
        }
 }
 
+/* called with rcu_read_lock */
 static void qeth_l3_add_vlan_mc(struct qeth_card *card)
 {
        struct in_device *in_dev;
@@ -1652,19 +1654,14 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card)
        for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
                struct net_device *netdev;
 
-               rcu_read_lock();
                netdev = __vlan_find_dev_deep(card->dev, vid);
-               rcu_read_unlock();
                if (netdev == NULL ||
                    !(netdev->flags & IFF_UP))
                        continue;
-               in_dev = in_dev_get(netdev);
+               in_dev = __in_dev_get_rcu(netdev);
                if (!in_dev)
                        continue;
-               rcu_read_lock();
                qeth_l3_add_mc(card, in_dev);
-               rcu_read_unlock();
-               in_dev_put(in_dev);
        }
 }
 
@@ -1673,14 +1670,14 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
        struct in_device *in4_dev;
 
        QETH_CARD_TEXT(card, 4, "chkmcv4");
-       in4_dev = in_dev_get(card->dev);
-       if (in4_dev == NULL)
-               return;
        rcu_read_lock();
+       in4_dev = __in_dev_get_rcu(card->dev);
+       if (in4_dev == NULL)
+               goto unlock;
        qeth_l3_add_mc(card, in4_dev);
        qeth_l3_add_vlan_mc(card);
+unlock:
        rcu_read_unlock();
-       in_dev_put(in4_dev);
 }
 
 #ifdef CONFIG_QETH_IPV6
@@ -1705,6 +1702,7 @@ static void qeth_l3_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
        }
 }
 
+/* called with rcu_read_lock */
 static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
 {
        struct inet6_dev *in_dev;
@@ -1741,10 +1739,12 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
        in6_dev = in6_dev_get(card->dev);
        if (in6_dev == NULL)
                return;
+       rcu_read_lock();
        read_lock_bh(&in6_dev->lock);
        qeth_l3_add_mc6(card, in6_dev);
        qeth_l3_add_vlan_mc6(card);
        read_unlock_bh(&in6_dev->lock);
+       rcu_read_unlock();
        in6_dev_put(in6_dev);
 }
 #endif /* CONFIG_QETH_IPV6 */
@@ -1813,8 +1813,10 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
 static void qeth_l3_free_vlan_addresses(struct qeth_card *card,
                        unsigned short vid)
 {
+       rcu_read_lock();
        qeth_l3_free_vlan_addresses4(card, vid);
        qeth_l3_free_vlan_addresses6(card, vid);
+       rcu_read_unlock();
 }
 
 static int qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
@@ -3387,8 +3389,10 @@ contin:
                QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
        if (!card->options.sniffer) {
                rc = qeth_l3_start_ipassists(card);
-               if (rc)
+               if (rc) {
                        QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+                       goto out_remove;
+               }
                rc = qeth_l3_setrouting_v4(card);
                if (rc)
                        QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
@@ -3510,12 +3514,9 @@ static int qeth_l3_recover(void *ptr)
                dev_info(&card->gdev->dev,
                        "Device successfully recovered!\n");
        else {
-               if (rtnl_trylock()) {
-                       dev_close(card->dev);
-                       rtnl_unlock();
-                       dev_warn(&card->gdev->dev, "The qeth device driver "
+               qeth_close_dev(card);
+               dev_warn(&card->gdev->dev, "The qeth device driver "
                                "failed to recover an error on the device\n");
-               }
        }
        qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
        qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
index 5d6f2ec1c705f4ede0ced96ca75efdf8495879d6..5ff3a4f1944310e1aa751cae74e30b3e069fd7dd 100644 (file)
@@ -136,6 +136,11 @@ config SSB_DRIVER_MIPS
 
          If unsure, say N
 
+config SSB_SFLASH
+       bool "SSB serial flash support"
+       depends on SSB_DRIVER_MIPS && BROKEN
+       default y
+
 # Assumption: We are on embedded, if we compile the MIPS core.
 config SSB_EMBEDDED
        bool
index 9159ba77c388086a06196767da05d87150d3aacd..b1ddc116d387c47119408ed07d71d3274cce0691 100644 (file)
@@ -11,6 +11,7 @@ ssb-$(CONFIG_SSB_SDIOHOST)            += sdio.o
 # built-in drivers
 ssb-y                                  += driver_chipcommon.o
 ssb-y                                  += driver_chipcommon_pmu.o
+ssb-$(CONFIG_SSB_SFLASH)               += driver_chipcommon_sflash.o
 ssb-$(CONFIG_SSB_DRIVER_MIPS)          += driver_mipscore.o
 ssb-$(CONFIG_SSB_DRIVER_EXTIF)         += driver_extif.o
 ssb-$(CONFIG_SSB_DRIVER_PCICORE)       += driver_pcicore.o
diff --git a/drivers/ssb/driver_chipcommon_sflash.c b/drivers/ssb/driver_chipcommon_sflash.c
new file mode 100644 (file)
index 0000000..720665c
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Sonics Silicon Backplane
+ * ChipCommon serial flash interface
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+struct ssb_sflash_tbl_e {
+       char *name;
+       u32 id;
+       u32 blocksize;
+       u16 numblocks;
+};
+
+static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
+       { "M25P20", 0x11, 0x10000, 4, },
+       { "M25P40", 0x12, 0x10000, 8, },
+
+       { "M25P16", 0x14, 0x10000, 32, },
+       { "M25P32", 0x15, 0x10000, 64, },
+       { "M25P64", 0x16, 0x10000, 128, },
+       { "M25FL128", 0x17, 0x10000, 256, },
+       { 0 },
+};
+
+static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
+       { "SST25WF512", 1, 0x1000, 16, },
+       { "SST25VF512", 0x48, 0x1000, 16, },
+       { "SST25WF010", 2, 0x1000, 32, },
+       { "SST25VF010", 0x49, 0x1000, 32, },
+       { "SST25WF020", 3, 0x1000, 64, },
+       { "SST25VF020", 0x43, 0x1000, 64, },
+       { "SST25WF040", 4, 0x1000, 128, },
+       { "SST25VF040", 0x44, 0x1000, 128, },
+       { "SST25VF040B", 0x8d, 0x1000, 128, },
+       { "SST25WF080", 5, 0x1000, 256, },
+       { "SST25VF080B", 0x8e, 0x1000, 256, },
+       { "SST25VF016", 0x41, 0x1000, 512, },
+       { "SST25VF032", 0x4a, 0x1000, 1024, },
+       { "SST25VF064", 0x4b, 0x1000, 2048, },
+       { 0 },
+};
+
+static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
+       { "AT45DB011", 0xc, 256, 512, },
+       { "AT45DB021", 0x14, 256, 1024, },
+       { "AT45DB041", 0x1c, 256, 2048, },
+       { "AT45DB081", 0x24, 256, 4096, },
+       { "AT45DB161", 0x2c, 512, 4096, },
+       { "AT45DB321", 0x34, 512, 8192, },
+       { "AT45DB642", 0x3c, 1024, 8192, },
+       { 0 },
+};
+
+static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
+{
+       int i;
+       chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
+                      SSB_CHIPCO_FLASHCTL_START | opcode);
+       for (i = 0; i < 1000; i++) {
+               if (!(chipco_read32(cc, SSB_CHIPCO_FLASHCTL) &
+                     SSB_CHIPCO_FLASHCTL_BUSY))
+                       return;
+               cpu_relax();
+       }
+       pr_err("SFLASH control command failed (timeout)!\n");
+}
+
+/* Initialize serial flash access */
+int ssb_sflash_init(struct ssb_chipcommon *cc)
+{
+       struct ssb_sflash_tbl_e *e;
+       u32 id, id2;
+
+       switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
+       case SSB_CHIPCO_FLASHT_STSER:
+               ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
+
+               chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
+               ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
+               id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
+
+               chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
+               ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
+               id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
+
+               switch (id) {
+               case 0xbf:
+                       for (e = ssb_sflash_sst_tbl; e->name; e++) {
+                               if (e->id == id2)
+                                       break;
+                       }
+                       break;
+               case 0x13:
+                       return -ENOTSUPP;
+               default:
+                       for (e = ssb_sflash_st_tbl; e->name; e++) {
+                               if (e->id == id)
+                                       break;
+                       }
+                       break;
+               }
+               if (!e->name) {
+                       pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n",
+                              id, id2);
+                       return -ENOTSUPP;
+               }
+
+               break;
+       case SSB_CHIPCO_FLASHT_ATSER:
+               ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
+               id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
+
+               for (e = ssb_sflash_at_tbl; e->name; e++) {
+                       if (e->id == id)
+                               break;
+               }
+               if (!e->name) {
+                       pr_err("Unsupported Atmel serial flash (id: 0x%X)\n",
+                              id);
+                       return -ENOTSUPP;
+               }
+
+               break;
+       default:
+               pr_err("Unsupported flash type\n");
+               return -ENOTSUPP;
+       }
+
+       pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
+               e->name, e->blocksize, e->numblocks);
+
+       pr_err("Serial flash support is not implemented yet!\n");
+
+       return -ENOTSUPP;
+}
index 5bd05b136d22ef80b2cd93f78b65d6ef60640473..2a7684c90243f78fce00c314bc56bff701b671ab 100644 (file)
@@ -203,7 +203,8 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
        switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
        case SSB_CHIPCO_FLASHT_STSER:
        case SSB_CHIPCO_FLASHT_ATSER:
-               pr_err("Serial flash not supported\n");
+               pr_debug("Found serial flash\n");
+               ssb_sflash_init(&bus->chipco);
                break;
        case SSB_CHIPCO_FLASHT_PARA:
                pr_debug("Found parallel flash\n");
index 6c10b66c796cf7ee23ae3e9334086034198e911c..77d942630750c5ca7bd7ae50d2aacd1f4bc377f0 100644 (file)
@@ -217,6 +217,17 @@ extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
                                             u32 ticks);
 extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
 
+/* driver_chipcommon_sflash.c */
+#ifdef CONFIG_SSB_SFLASH
+int ssb_sflash_init(struct ssb_chipcommon *cc);
+#else
+static inline int ssb_sflash_init(struct ssb_chipcommon *cc)
+{
+       pr_err("Serial flash not supported\n");
+       return 0;
+}
+#endif /* CONFIG_SSB_SFLASH */
+
 #ifdef CONFIG_SSB_DRIVER_EXTIF
 extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks);
 extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
index a3b91c7ee8ff896102418c4c82b756574df2922a..4e470d4bb4e8f297c15ab40825f66e0ab7c9c239 100644 (file)
@@ -145,8 +145,8 @@ static void bcm_get_drvinfo(struct net_device *dev,
        struct bcm_interface_adapter *psIntfAdapter = Adapter->pvInterfaceAdapter;
        struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u",
                 Adapter->uiFlashLayoutMajorVersion,
                 Adapter->uiFlashLayoutMinorVersion);
index d0dabcf015a9b50bc453547477dbf9bd2ab6c3d2..fed78865adc6b3b5e7e025dd95fc49eaa5defe84 100644 (file)
@@ -157,12 +157,12 @@ static int ueth_change_mtu(struct net_device *net, int new_mtu)
 
 static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
-       struct eth_dev  *dev = netdev_priv(net);
+       struct eth_dev *dev = netdev_priv(net);
 
-       strlcpy(p->driver, "g_ether", sizeof p->driver);
-       strlcpy(p->version, UETH__VERSION, sizeof p->version);
-       strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
-       strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
+       strlcpy(p->driver, "g_ether", sizeof(p->driver));
+       strlcpy(p->version, UETH__VERSION, sizeof(p->version));
+       strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+       strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
 }
 
 /* REVISIT can also support:
index 84bbcd48e26489753ed30581980c93864fb3ace3..a0a30b3f2dcd3d6978653dc9cfcd0296e9e590dc 100644 (file)
@@ -3560,15 +3560,15 @@ static void et131x_get_regs(struct net_device *netdev,
        regs_buff[num++] = readl(&aregs->rxdma.fbr1_min_des);
 }
 
-#define ET131X_DRVINFO_LEN 32 /* value from ethtool.h */
 static void et131x_get_drvinfo(struct net_device *netdev,
                               struct ethtool_drvinfo *info)
 {
        struct et131x_adapter *adapter = netdev_priv(netdev);
 
-       strncpy(info->driver, DRIVER_NAME, ET131X_DRVINFO_LEN);
-       strncpy(info->version, DRIVER_VERSION, ET131X_DRVINFO_LEN);
-       strncpy(info->bus_info, pci_name(adapter->pdev), ET131X_DRVINFO_LEN);
+       strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(adapter->pdev),
+               sizeof(info->bus_info));
 }
 
 static struct ethtool_ops et131x_ethtool_ops = {
@@ -3917,7 +3917,7 @@ static int et131x_mii_probe(struct net_device *netdev)
        }
 
        phydev = phy_connect(netdev, dev_name(&phydev->dev),
-                       &et131x_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+                            &et131x_adjust_link, PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
                dev_err(&adapter->pdev->dev, "Could not attach to PHY\n");
index 86a680c09ba2a7e2bf62276d1f85e3415c0827c6..67ca5c990437f09c4cabe617145ec4ea0e3a0db5 100644 (file)
@@ -2077,11 +2077,12 @@ static void ft1000_get_drvinfo(struct net_device *dev,
        struct ft1000_info *ft_info;
        ft_info = netdev_priv(dev);
 
-       snprintf(info->driver, 32, "ft1000");
-       snprintf(info->bus_info, ETHTOOL_BUSINFO_LEN, "PCMCIA 0x%lx",
+       strlcpy(info->driver, "ft1000", sizeof(info->driver));
+       snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx",
                 dev->base_addr);
-       snprintf(info->fw_version, 32, "%d.%d.%d.%d", ft_info->DspVer[0],
-                ft_info->DspVer[1], ft_info->DspVer[2], ft_info->DspVer[3]);
+       snprintf(info->fw_version, sizeof(info->fw_version), "%d.%d.%d.%d",
+                ft_info->DspVer[0], ft_info->DspVer[1], ft_info->DspVer[2],
+                ft_info->DspVer[3]);
 }
 
 static u32 ft1000_get_link(struct net_device *dev)
index f15b31b37ca50920a6e4a314eea40f9e8d3185d5..83b103091cf2e59e39c28ef6780e53ee6d35f86a 100644 (file)
@@ -46,9 +46,9 @@
 static void cvm_oct_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "cavium-ethernet");
-       strcpy(info->version, OCTEON_ETHERNET_VERSION);
-       strcpy(info->bus_info, "Builtin");
+       strlcpy(info->driver, "cavium-ethernet", sizeof(info->driver));
+       strlcpy(info->version, OCTEON_ETHERNET_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, "Builtin", sizeof(info->bus_info));
 }
 
 static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index ef32dc1bbc802901566da71804a5001b8c709396..9a2ec251ae4d5fad3e1b33077bfb280afb5806c6 100644 (file)
@@ -453,12 +453,10 @@ int cvm_oct_common_init(struct net_device *dev)
        if (priv->of_node)
                mac = of_get_mac_address(priv->of_node);
 
-       if (mac && is_valid_ether_addr(mac)) {
+       if (mac && is_valid_ether_addr(mac))
                memcpy(dev->dev_addr, mac, ETH_ALEN);
-               dev->addr_assign_type &= ~NET_ADDR_RANDOM;
-       } else {
+       else
                eth_hw_addr_random(dev);
-       }
 
        /*
         * Force the interface to use the POW send if always_use_pow
index 36452fb7cef8e0a6000f4d91b96306dcb323636e..0cfb3ecaadee53a724d886ce0c56d5bd7f431875 100644 (file)
@@ -34,9 +34,9 @@ static void rtl819x_ethtool_get_drvinfo(struct net_device *dev,
 {
        struct r8192_priv *priv = rtllib_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(priv->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info));
 }
 
 static u32 rtl819x_ethtool_get_link(struct net_device *dev)
index fb421407e10659318fe8f1f5d77e03a1be96404a..235cc2a7ffe68d15603c716e6fce78934df05f97 100644 (file)
@@ -457,17 +457,17 @@ int wl_close( struct net_device *dev )
 
 static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-    strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
-    strncpy(info->version, DRV_VERSION_STR, sizeof(info->version) - 1);
-//     strncpy(info.fw_version, priv->fw_name,
-//     sizeof(info.fw_version) - 1);
+    strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+    strlcpy(info->version, DRV_VERSION_STR, sizeof(info->version));
+//     strlcpy(info.fw_version, priv->fw_name,
+//     sizeof(info.fw_version));
 
     if (dev->dev.parent) {
        dev_set_name(dev->dev.parent, "%s", info->bus_info);
-       //strncpy(info->bus_info, dev->dev.parent->bus_id,
-       //      sizeof(info->bus_info) - 1);
+       //strlcpy(info->bus_info, dev->dev.parent->bus_id,
+       //      sizeof(info->bus_info));
     } else {
-       snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+       snprintf(info->bus_info, sizeof(info->bus_info),
                "PCMCIA FIXME");
 //                 "PCMCIA 0x%lx", priv->hw.iobase);
     }
index 4ec3c0d7a18b84bb895262de69bf080886391025..a0aa721d8b216bb29350be51270a9e4c6330eaed 100644 (file)
@@ -159,12 +159,12 @@ static int ueth_change_mtu(struct net_device *net, int new_mtu)
 
 static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
-       struct eth_dev  *dev = netdev_priv(net);
+       struct eth_dev *dev = netdev_priv(net);
 
-       strlcpy(p->driver, "g_ether", sizeof p->driver);
-       strlcpy(p->version, UETH__VERSION, sizeof p->version);
-       strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
-       strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
+       strlcpy(p->driver, "g_ether", sizeof(p->driver));
+       strlcpy(p->version, UETH__VERSION, sizeof(p->version));
+       strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+       strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
 }
 
 /* REVISIT can also support:
index 9a0e3fa3ca9539123f1a5494cb0007c17b4c9a26..ee332fab825bcbd44368f616fd0dd062d54fa177 100644 (file)
@@ -634,4 +634,6 @@ extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
                                       u32 offset, u32 mask, u32 set);
 extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
 
+extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
+
 #endif /* LINUX_BCMA_DRIVER_CC_H_ */
index 0baf8a56b7947b7300e5bb2b1b0a8dd5ef188483..0d1ea297851aaf3492c208d1dd3c411745348a44 100644 (file)
@@ -28,6 +28,7 @@
 #define BCMA_MIPS_MIPS74K_GPIOEN       0x0048
 #define BCMA_MIPS_MIPS74K_CLKCTLST     0x01E0
 
+#define BCMA_MIPS_OOBSELINA74          0x004
 #define BCMA_MIPS_OOBSELOUTA30         0x100
 
 struct bcma_device;
@@ -36,7 +37,6 @@ struct bcma_drv_mips {
        struct bcma_device *core;
        u8 setup_done:1;
        u8 early_setup_done:1;
-       unsigned int assigned_irqs;
 };
 
 #ifdef CONFIG_BCMA_DRIVER_MIPS
@@ -49,6 +49,6 @@ static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
 
 extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
 
-extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+extern unsigned int bcma_core_irq(struct bcma_device *core);
 
 #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
index c48d98d27b770ee8f13a6ff26aa918aeb89d66be..424760f01b9d7b71354e94ba8ab8e62c57bd7c04 100644 (file)
@@ -179,6 +179,8 @@ struct pci_dev;
 #define BCMA_CORE_PCI_CFG_FUN_MASK             7       /* Function mask */
 #define BCMA_CORE_PCI_CFG_OFF_MASK             0xfff   /* Register mask */
 
+#define BCMA_CORE_PCI_CFG_DEVCTRL              0xd8
+
 /* PCIE Root Capability Register bits (Host mode only) */
 #define BCMA_CORE_PCI_RC_CRS_VISIBILITY                0x0001
 
index 2b2fc345afca9103e6f9adf13610524b4ddf5844..fb0ab651a04196ac247b718221cd857de0cc5365 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/can.h>
 #include <linux/can/netlink.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 
 /*
  * CAN mode
@@ -52,6 +53,13 @@ struct can_priv {
 
        unsigned int echo_skb_max;
        struct sk_buff **echo_skb;
+
+#ifdef CONFIG_CAN_LEDS
+       struct led_trigger *tx_led_trig;
+       char tx_led_trig_name[CAN_LED_NAME_SZ];
+       struct led_trigger *rx_led_trig;
+       char rx_led_trig_name[CAN_LED_NAME_SZ];
+#endif
 };
 
 /*
@@ -98,6 +106,9 @@ u8 can_len2dlc(u8 len);
 struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
 void free_candev(struct net_device *dev);
 
+/* a candev safe wrapper around netdev_priv */
+struct can_priv *safe_candev_priv(struct net_device *dev);
+
 int open_candev(struct net_device *dev);
 void close_candev(struct net_device *dev);
 
diff --git a/include/linux/can/led.h b/include/linux/can/led.h
new file mode 100644 (file)
index 0000000..9c1167b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CAN_LED_H
+#define CAN_LED_H
+
+#include <linux/if.h>
+#include <linux/leds.h>
+
+enum can_led_event {
+       CAN_LED_EVENT_OPEN,
+       CAN_LED_EVENT_STOP,
+       CAN_LED_EVENT_TX,
+       CAN_LED_EVENT_RX,
+};
+
+#ifdef CONFIG_CAN_LEDS
+
+/* keep space for interface name + "-tx"/"-rx" suffix and null terminator */
+#define CAN_LED_NAME_SZ (IFNAMSIZ + 4)
+
+void can_led_event(struct net_device *netdev, enum can_led_event event);
+void devm_can_led_init(struct net_device *netdev);
+int __init can_led_notifier_init(void);
+void __exit can_led_notifier_exit(void);
+
+#else
+
+static inline void can_led_event(struct net_device *netdev,
+                                enum can_led_event event)
+{
+}
+static inline void devm_can_led_init(struct net_device *netdev)
+{
+}
+static inline int can_led_notifier_init(void)
+{
+       return 0;
+}
+static inline void can_led_notifier_exit(void)
+{
+}
+
+#endif
+
+#endif
diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
new file mode 100644 (file)
index 0000000..2f0543f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * linux/can/skb.h
+ *
+ * Definitions for the CAN network socket buffer
+ *
+ * Copyright (C) 2012 Oliver Hartkopp <socketcan@hartkopp.net>
+ *
+ */
+
+#ifndef CAN_SKB_H
+#define CAN_SKB_H
+
+#include <linux/types.h>
+#include <linux/can.h>
+
+/*
+ * The struct can_skb_priv is used to transport additional information along
+ * with the stored struct can(fd)_frame that can not be contained in existing
+ * struct sk_buff elements.
+ * N.B. that this information must not be modified in cloned CAN sk_buffs.
+ * To modify the CAN frame content or the struct can_skb_priv content
+ * skb_copy() needs to be used instead of skb_clone().
+ */
+
+/**
+ * struct can_skb_priv - private additional data inside CAN sk_buffs
+ * @ifindex:   ifindex of the first interface the CAN frame appeared on
+ * @cf:                align to the following CAN frame at skb->data
+ */
+struct can_skb_priv {
+       int ifindex;
+       struct can_frame cf[0];
+};
+
+static inline struct can_skb_priv *can_skb_prv(struct sk_buff *skb)
+{
+       return (struct can_skb_priv *)(skb->head);
+}
+
+static inline void can_skb_reserve(struct sk_buff *skb)
+{
+       skb_reserve(skb, sizeof(struct can_skb_priv));
+}
+
+#endif /* CAN_SKB_H */
index 243eea1e33d8021b685f46a736e726c74e083a22..c623861964e4c8d6773c632758770fe4d5ac03be 100644 (file)
@@ -40,6 +40,8 @@ extern int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
 extern void eth_header_cache_update(struct hh_cache *hh,
                                    const struct net_device *dev,
                                    const unsigned char *haddr);
+extern int eth_prepare_mac_addr_change(struct net_device *dev, void *p);
+extern void eth_commit_mac_addr_change(struct net_device *dev, void *p);
 extern int eth_mac_addr(struct net_device *dev, void *p);
 extern int eth_change_mtu(struct net_device *dev, int new_mtu);
 extern int eth_validate_addr(struct net_device *dev);
@@ -192,7 +194,7 @@ static inline void eth_zero_addr(u8 *addr)
  */
 static inline void eth_hw_addr_random(struct net_device *dev)
 {
-       dev->addr_assign_type |= NET_ADDR_RANDOM;
+       dev->addr_assign_type = NET_ADDR_RANDOM;
        eth_random_addr(dev->dev_addr);
 }
 
index f0859cc73861720a982c185a3422fe66efbe5415..ccf9ee1dca8cbce8941d8a42a3ebc32d21a71015 100644 (file)
@@ -180,7 +180,7 @@ struct ieee80211_hdr {
        u8 addr3[6];
        __le16 seq_ctrl;
        u8 addr4[6];
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_hdr_3addr {
        __le16 frame_control;
@@ -189,7 +189,7 @@ struct ieee80211_hdr_3addr {
        u8 addr2[6];
        u8 addr3[6];
        __le16 seq_ctrl;
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_qos_hdr {
        __le16 frame_control;
@@ -199,7 +199,7 @@ struct ieee80211_qos_hdr {
        u8 addr3[6];
        __le16 seq_ctrl;
        __le16 qos_ctrl;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
@@ -576,7 +576,7 @@ struct ieee80211s_hdr {
        __le32 seqnum;
        u8 eaddr1[6];
        u8 eaddr2[6];
-} __attribute__ ((packed));
+} __packed;
 
 /* Mesh flags */
 #define MESH_FLAGS_AE_A4       0x1
@@ -614,7 +614,7 @@ struct ieee80211_quiet_ie {
        u8 period;
        __le16 duration;
        __le16 offset;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ieee80211_msrment_ie
@@ -626,7 +626,7 @@ struct ieee80211_msrment_ie {
        u8 mode;
        u8 type;
        u8 request[0];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ieee80211_channel_sw_ie
@@ -637,7 +637,7 @@ struct ieee80211_channel_sw_ie {
        u8 mode;
        u8 new_ch_num;
        u8 count;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ieee80211_tim
@@ -650,7 +650,7 @@ struct ieee80211_tim_ie {
        u8 bitmap_ctrl;
        /* variable size: 1 - 251 bytes */
        u8 virtual_map[1];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ieee80211_meshconf_ie
@@ -665,7 +665,7 @@ struct ieee80211_meshconf_ie {
        u8 meshconf_auth;
        u8 meshconf_form;
        u8 meshconf_cap;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * enum mesh_config_capab_flags - Mesh Configuration IE capability field flags
@@ -695,12 +695,17 @@ struct ieee80211_rann_ie {
        __le32 rann_seq;
        __le32 rann_interval;
        __le32 rann_metric;
-} __attribute__ ((packed));
+} __packed;
 
 enum ieee80211_rann_flags {
        RANN_FLAG_IS_GATE = 1 << 0,
 };
 
+enum ieee80211_ht_chanwidth_values {
+       IEEE80211_HT_CHANWIDTH_20MHZ = 0,
+       IEEE80211_HT_CHANWIDTH_ANY = 1,
+};
+
 #define WLAN_SA_QUERY_TR_ID_LEN 2
 
 struct ieee80211_mgmt {
@@ -717,33 +722,33 @@ struct ieee80211_mgmt {
                        __le16 status_code;
                        /* possibly followed by Challenge text */
                        u8 variable[0];
-               } __attribute__ ((packed)) auth;
+               } __packed auth;
                struct {
                        __le16 reason_code;
-               } __attribute__ ((packed)) deauth;
+               } __packed deauth;
                struct {
                        __le16 capab_info;
                        __le16 listen_interval;
                        /* followed by SSID and Supported rates */
                        u8 variable[0];
-               } __attribute__ ((packed)) assoc_req;
+               } __packed assoc_req;
                struct {
                        __le16 capab_info;
                        __le16 status_code;
                        __le16 aid;
                        /* followed by Supported rates */
                        u8 variable[0];
-               } __attribute__ ((packed)) assoc_resp, reassoc_resp;
+               } __packed assoc_resp, reassoc_resp;
                struct {
                        __le16 capab_info;
                        __le16 listen_interval;
                        u8 current_ap[6];
                        /* followed by SSID and Supported rates */
                        u8 variable[0];
-               } __attribute__ ((packed)) reassoc_req;
+               } __packed reassoc_req;
                struct {
                        __le16 reason_code;
-               } __attribute__ ((packed)) disassoc;
+               } __packed disassoc;
                struct {
                        __le64 timestamp;
                        __le16 beacon_int;
@@ -751,11 +756,11 @@ struct ieee80211_mgmt {
                        /* followed by some of SSID, Supported rates,
                         * FH Params, DS Params, CF Params, IBSS Params, TIM */
                        u8 variable[0];
-               } __attribute__ ((packed)) beacon;
+               } __packed beacon;
                struct {
                        /* only variable items: SSID, Supported rates */
                        u8 variable[0];
-               } __attribute__ ((packed)) probe_req;
+               } __packed probe_req;
                struct {
                        __le64 timestamp;
                        __le16 beacon_int;
@@ -763,7 +768,7 @@ struct ieee80211_mgmt {
                        /* followed by some of SSID, Supported rates,
                         * FH Params, DS Params, CF Params, IBSS Params */
                        u8 variable[0];
-               } __attribute__ ((packed)) probe_resp;
+               } __packed probe_resp;
                struct {
                        u8 category;
                        union {
@@ -772,55 +777,59 @@ struct ieee80211_mgmt {
                                        u8 dialog_token;
                                        u8 status_code;
                                        u8 variable[0];
-                               } __attribute__ ((packed)) wme_action;
+                               } __packed wme_action;
                                struct{
                                        u8 action_code;
                                        u8 element_id;
                                        u8 length;
                                        struct ieee80211_channel_sw_ie sw_elem;
-                               } __attribute__((packed)) chan_switch;
+                               } __packed chan_switch;
                                struct{
                                        u8 action_code;
                                        u8 dialog_token;
                                        u8 element_id;
                                        u8 length;
                                        struct ieee80211_msrment_ie msr_elem;
-                               } __attribute__((packed)) measurement;
+                               } __packed measurement;
                                struct{
                                        u8 action_code;
                                        u8 dialog_token;
                                        __le16 capab;
                                        __le16 timeout;
                                        __le16 start_seq_num;
-                               } __attribute__((packed)) addba_req;
+                               } __packed addba_req;
                                struct{
                                        u8 action_code;
                                        u8 dialog_token;
                                        __le16 status;
                                        __le16 capab;
                                        __le16 timeout;
-                               } __attribute__((packed)) addba_resp;
+                               } __packed addba_resp;
                                struct{
                                        u8 action_code;
                                        __le16 params;
                                        __le16 reason_code;
-                               } __attribute__((packed)) delba;
+                               } __packed delba;
                                struct {
                                        u8 action_code;
                                        u8 variable[0];
-                               } __attribute__((packed)) self_prot;
+                               } __packed self_prot;
                                struct{
                                        u8 action_code;
                                        u8 variable[0];
-                               } __attribute__((packed)) mesh_action;
+                               } __packed mesh_action;
                                struct {
                                        u8 action;
                                        u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
-                               } __attribute__ ((packed)) sa_query;
+                               } __packed sa_query;
                                struct {
                                        u8 action;
                                        u8 smps_control;
-                               } __attribute__ ((packed)) ht_smps;
+                               } __packed ht_smps;
+                               struct {
+                                       u8 action_code;
+                                       u8 chanwidth;
+                               } __packed ht_notify_cw;
                                struct {
                                        u8 action_code;
                                        u8 dialog_token;
@@ -828,9 +837,9 @@ struct ieee80211_mgmt {
                                        u8 variable[0];
                                } __packed tdls_discover_resp;
                        } u;
-               } __attribute__ ((packed)) action;
+               } __packed action;
        } u;
-} __attribute__ ((packed));
+} __packed;
 
 /* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */
 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
@@ -846,7 +855,7 @@ struct ieee80211_mmie {
        __le16 key_id;
        u8 sequence_number[6];
        u8 mic[8];
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_vendor_ie {
        u8 element_id;
@@ -861,20 +870,20 @@ struct ieee80211_rts {
        __le16 duration;
        u8 ra[6];
        u8 ta[6];
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_cts {
        __le16 frame_control;
        __le16 duration;
        u8 ra[6];
-} __attribute__ ((packed));
+} __packed;
 
 struct ieee80211_pspoll {
        __le16 frame_control;
        __le16 aid;
        u8 bssid[6];
        u8 ta[6];
-} __attribute__ ((packed));
+} __packed;
 
 /* TDLS */
 
@@ -967,7 +976,7 @@ struct ieee80211_bar {
        __u8 ta[6];
        __le16 control;
        __le16 start_seq_num;
-} __attribute__((packed));
+} __packed;
 
 /* 802.11 BAR control masks */
 #define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL   0x0000
@@ -992,7 +1001,7 @@ struct ieee80211_mcs_info {
        __le16 rx_highest;
        u8 tx_params;
        u8 reserved[3];
-} __attribute__((packed));
+} __packed;
 
 /* 802.11n HT capability MSC set */
 #define IEEE80211_HT_MCS_RX_HIGHEST_MASK       0x3ff
@@ -1031,7 +1040,7 @@ struct ieee80211_ht_cap {
        __le16 extended_ht_cap_info;
        __le32 tx_BF_cap_info;
        u8 antenna_selection_info;
-} __attribute__ ((packed));
+} __packed;
 
 /* 802.11n HT capabilities masks (for cap_info) */
 #define IEEE80211_HT_CAP_LDPC_CODING           0x0001
@@ -1102,7 +1111,7 @@ struct ieee80211_ht_operation {
        __le16 operation_mode;
        __le16 stbc_param;
        u8 basic_set[16];
-} __attribute__ ((packed));
+} __packed;
 
 /* for ht_param */
 #define IEEE80211_HT_PARAM_CHA_SEC_OFFSET              0x03
@@ -1311,16 +1320,21 @@ struct ieee80211_vht_operation {
 #define WLAN_CAPABILITY_SPECTRUM_MGMT  (1<<8)
 #define WLAN_CAPABILITY_QOS            (1<<9)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME        (1<<10)
+#define WLAN_CAPABILITY_APSD           (1<<11)
+#define WLAN_CAPABILITY_RADIO_MEASURE  (1<<12)
 #define WLAN_CAPABILITY_DSSS_OFDM      (1<<13)
+#define WLAN_CAPABILITY_DEL_BACK       (1<<14)
+#define WLAN_CAPABILITY_IMM_BACK       (1<<15)
 
 /* DMG (60gHz) 802.11ad */
 /* type - bits 0..1 */
+#define WLAN_CAPABILITY_DMG_TYPE_MASK          (3<<0)
 #define WLAN_CAPABILITY_DMG_TYPE_IBSS          (1<<0) /* Tx by: STA */
 #define WLAN_CAPABILITY_DMG_TYPE_PBSS          (2<<0) /* Tx by: PCP */
 #define WLAN_CAPABILITY_DMG_TYPE_AP            (3<<0) /* Tx by: AP */
 
 #define WLAN_CAPABILITY_DMG_CBAP_ONLY          (1<<2)
-#define WLAN_CAPABILITY_DMG_CBAP_SOURCE        (1<<3)
+#define WLAN_CAPABILITY_DMG_CBAP_SOURCE                (1<<3)
 #define WLAN_CAPABILITY_DMG_PRIVACY            (1<<4)
 #define WLAN_CAPABILITY_DMG_ECPAC              (1<<5)
 
@@ -1834,14 +1848,14 @@ struct ieee80211_country_ie_triplet {
                        u8 first_channel;
                        u8 num_channels;
                        s8 max_power;
-               } __attribute__ ((packed)) chans;
+               } __packed chans;
                struct {
                        u8 reg_extension_id;
                        u8 reg_class;
                        u8 coverage_class;
-               } __attribute__ ((packed)) ext;
+               } __packed ext;
        };
-} __attribute__ ((packed));
+} __packed;
 
 enum ieee80211_timeout_interval_type {
        WLAN_TIMEOUT_REASSOC_DEADLINE = 1 /* 802.11r */,
index 9e2ae26fb5981703159c27cc60e7c73cf6d311f6..a16e19349ec0f132849288df8c2a01ed5ac59d4e 100644 (file)
 
 #include <uapi/linux/in6.h>
 
+/* IPv6 Wildcard Address (::) and Loopback Address (::1) defined in RFC2553
+ * NOTE: Be aware the IN6ADDR_* constants and in6addr_* externals are defined
+ * in network byte order, not in host byte order as are the IPv4 equivalents
+ */
 extern const struct in6_addr in6addr_any;
 #define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
 extern const struct in6_addr in6addr_loopback;
index a9d828976a77a56b400ffd3f4e7a56915f3762a5..ea1e3b8638900a5d7f5cf46e49eec37c3274f9a9 100644 (file)
@@ -166,6 +166,12 @@ struct in_ifaddr {
        unsigned char           ifa_flags;
        unsigned char           ifa_prefixlen;
        char                    ifa_label[IFNAMSIZ];
+
+       /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
+       __u32                   ifa_valid_lft;
+       __u32                   ifa_preferred_lft;
+       unsigned long           ifa_cstamp; /* created timestamp */
+       unsigned long           ifa_tstamp; /* updated timestamp */
 };
 
 extern int register_inetaddr_notifier(struct notifier_block *nb);
index faed1e357dd6c605cdea3445a803e167d17d3e0c..e971e3742172c0c7817d1933fffa8bcf67f13492 100644 (file)
@@ -77,11 +77,6 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb)
        return (struct ipv6hdr *)skb_transport_header(skb);
 }
 
-static inline __u8 ipv6_tclass(const struct ipv6hdr *iph)
-{
-       return (ntohl(*(__be32 *)iph) >> 20) & 0xff;
-}
-
 /* 
    This structure contains results of exthdrs parsing
    as offsets from skb->nh.
@@ -89,7 +84,7 @@ static inline __u8 ipv6_tclass(const struct ipv6hdr *iph)
 
 struct inet6_skb_parm {
        int                     iif;
-       __u16                   ra;
+       __be16                  ra;
        __u16                   hop;
        __u16                   dst0;
        __u16                   srcrt;
@@ -105,6 +100,7 @@ struct inet6_skb_parm {
 #define IP6SKB_XFRM_TRANSFORMED        1
 #define IP6SKB_FORWARDED       2
 #define IP6SKB_REROUTED                4
+#define IP6SKB_ROUTERALERT     8
 };
 
 #define IP6CB(skb)     ((struct inet6_skb_parm*)((skb)->cb))
index adfe8c058f298ffb4f619688676423ea67838997..9dbb41a4e2504632174803d1f31f4c49c61d160d 100644 (file)
 #define PHY_ID_KSZ8021         0x00221555
 #define PHY_ID_KSZ8041         0x00221510
 #define PHY_ID_KSZ8051         0x00221550
-/* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */
+/* same id: ks8001 Rev. A/B, and ks8721 Rev 3. */
 #define PHY_ID_KSZ8001         0x0022161A
+/* same id: KS8081, KS8091 */
+#define PHY_ID_KSZ8081         0x00221560
+#define PHY_ID_KSZ8061         0x00221570
+#define PHY_ID_KSZ9031         0x00221620
+
+#define PHY_ID_KSZ886X         0x00221430
+#define PHY_ID_KSZ8863         0x00221435
 
 /* struct phy_device dev_flags definitions */
 #define MICREL_PHY_50MHZ_CLK   0x00000001
index ea00d9162ee57c858954e8ec8cd36d4ebf0f15e0..79aaa9fc1a15d6ed7caac2b147ae030b18da060a 100644 (file)
@@ -9,7 +9,7 @@
 #ifdef CONFIG_IP_MROUTE
 static inline int ip_mroute_opt(int opt)
 {
-       return (opt >= MRT_BASE) && (opt <= MRT_BASE + 10);
+       return (opt >= MRT_BASE) && (opt <= MRT_MAX);
 }
 #else
 static inline int ip_mroute_opt(int opt)
index a223561ba12e397e89d23dcd2ed3fd3e4311645a..66982e7640514389098c140a39665f95261071d8 100644 (file)
@@ -10,7 +10,7 @@
 #ifdef CONFIG_IPV6_MROUTE
 static inline int ip6_mroute_opt(int opt)
 {
-       return (opt >= MRT6_BASE) && (opt <= MRT6_BASE + 10);
+       return (opt >= MRT6_BASE) && (opt <= MRT6_MAX);
 }
 #else
 static inline int ip6_mroute_opt(int opt)
index 9ef07d0868b6012da1d1089daa2c9b0d7d304389..85b0949d9946808b7f5dbc01c3935691f94fd9dc 100644 (file)
@@ -67,6 +67,8 @@ extern void netdev_set_default_ethtool_ops(struct net_device *dev,
 #define NET_ADDR_PERM          0       /* address is permanent (default) */
 #define NET_ADDR_RANDOM                1       /* address is generated randomly */
 #define NET_ADDR_STOLEN                2       /* address is stolen from other device */
+#define NET_ADDR_SET           3       /* address is set using
+                                        * dev_set_mac_address() */
 
 /* Backlog congestion levels */
 #define NET_RX_SUCCESS         0       /* keep 'em coming, baby */
@@ -859,8 +861,7 @@ struct netdev_fcoe_hbainfo {
  *     flow_id is a flow ID to be passed to rps_may_expire_flow() later.
  *     Return the filter ID on success, or a negative error code.
  *
- *     Slave management functions (for bridge, bonding, etc). User should
- *     call netdev_set_master() to set dev->master properly.
+ *     Slave management functions (for bridge, bonding, etc).
  * int (*ndo_add_slave)(struct net_device *dev, struct net_device *slave_dev);
  *     Called to make another netdev an underling.
  *
@@ -894,6 +895,14 @@ struct netdev_fcoe_hbainfo {
  * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
  * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
  *                          struct net_device *dev)
+ *
+ * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
+ *     Called to change device carrier. Soft-devices (like dummy, team, etc)
+ *     which do not represent real hardware may define this to allow their
+ *     userspace components to manage their virtual carrier state. Devices
+ *     that determine carrier state from physical hardware properties (eg
+ *     network cables) or protocol-dependent mechanisms (eg
+ *     USB_CDC_NOTIFY_NETWORK_CONNECTION) should NOT implement this function.
  */
 struct net_device_ops {
        int                     (*ndo_init)(struct net_device *dev);
@@ -1011,6 +1020,8 @@ struct net_device_ops {
        int                     (*ndo_bridge_getlink)(struct sk_buff *skb,
                                                      u32 pid, u32 seq,
                                                      struct net_device *dev);
+       int                     (*ndo_change_carrier)(struct net_device *dev,
+                                                     bool new_carrier);
 };
 
 /*
@@ -1161,9 +1172,7 @@ struct net_device {
                                                 * avoid dirtying this cache line.
                                                 */
 
-       struct net_device       *master; /* Pointer to master device of a group,
-                                         * which this device is member of.
-                                         */
+       struct list_head        upper_dev_list; /* List of upper devices */
 
        /* Interface address info used in eth_type_trans() */
        unsigned char           *dev_addr;      /* hw address, (before bcast
@@ -1263,7 +1272,7 @@ struct net_device {
        void (*destructor)(struct net_device *dev);
 
 #ifdef CONFIG_NETPOLL
-       struct netpoll_info     *npinfo;
+       struct netpoll_info __rcu       *npinfo;
 #endif
 
 #ifdef CONFIG_NET_NS
@@ -1277,6 +1286,7 @@ struct net_device {
                struct pcpu_lstats __percpu     *lstats; /* loopback stats */
                struct pcpu_tstats __percpu     *tstats; /* tunnel stats */
                struct pcpu_dstats __percpu     *dstats; /* dummy stats */
+               struct pcpu_vstats __percpu     *vstats; /* veth stats */
        };
        /* GARP */
        struct garp_port __rcu  *garp_port;
@@ -1396,6 +1406,7 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
 
 extern struct netdev_queue *netdev_pick_tx(struct net_device *dev,
                                           struct sk_buff *skb);
+extern u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb);
 
 /*
  * Net namespace inlines
@@ -2095,6 +2106,18 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
                __netif_schedule(txq->qdisc);
 }
 
+#ifdef CONFIG_XPS
+extern int netif_set_xps_queue(struct net_device *dev, struct cpumask *mask,
+                              u16 index);
+#else
+static inline int netif_set_xps_queue(struct net_device *dev,
+                                     struct cpumask *mask,
+                                     u16 index)
+{
+       return 0;
+}
+#endif
+
 /*
  * Returns a Tx hash for the given packet when dev->real_num_tx_queues is used
  * as a distribution range limit for the returned value.
@@ -2197,6 +2220,8 @@ extern int                dev_set_mtu(struct net_device *, int);
 extern void            dev_set_group(struct net_device *, int);
 extern int             dev_set_mac_address(struct net_device *,
                                            struct sockaddr *);
+extern int             dev_change_carrier(struct net_device *,
+                                          bool new_carrier);
 extern int             dev_hard_start_xmit(struct sk_buff *skb,
                                            struct net_device *dev,
                                            struct netdev_queue *txq);
@@ -2624,9 +2649,18 @@ extern int               netdev_max_backlog;
 extern int             netdev_tstamp_prequeue;
 extern int             weight_p;
 extern int             bpf_jit_enable;
-extern int             netdev_set_master(struct net_device *dev, struct net_device *master);
-extern int netdev_set_bond_master(struct net_device *dev,
-                                 struct net_device *master);
+
+extern bool netdev_has_upper_dev(struct net_device *dev,
+                                struct net_device *upper_dev);
+extern bool netdev_has_any_upper_dev(struct net_device *dev);
+extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
+extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
+extern int netdev_upper_dev_link(struct net_device *dev,
+                                struct net_device *upper_dev);
+extern int netdev_master_upper_dev_link(struct net_device *dev,
+                                       struct net_device *upper_dev);
+extern void netdev_upper_dev_unlink(struct net_device *dev,
+                                   struct net_device *upper_dev);
 extern int skb_checksum_help(struct sk_buff *skb);
 extern struct sk_buff *skb_gso_segment(struct sk_buff *skb,
        netdev_features_t features);
index 387bdd02945d13555d79e0becd9cb0bc1fb5737f..ba7f571a2b1cba1f2381ee50c7030946543f31ac 100644 (file)
@@ -4,12 +4,15 @@
 
 #include <net/netfilter/nf_conntrack_expect.h>
 
+#include <linux/types.h>
+
 #define SIP_PORT       5060
 #define SIP_TIMEOUT    3600
 
 struct nf_ct_sip_master {
        unsigned int    register_cseq;
        unsigned int    invite_cseq;
+       __be16          forced_dport;
 };
 
 enum sip_expectation_classes {
index 66d5379c305e60d17dcde8b60d286f0b57b23a16..f54c3bb6a22b52b05da086e3033d368e0cb9e494 100644 (file)
 #include <linux/rcupdate.h>
 #include <linux/list.h>
 
+union inet_addr {
+       __u32           all[4];
+       __be32          ip;
+       __be32          ip6[4];
+       struct in_addr  in;
+       struct in6_addr in6;
+};
+
 struct netpoll {
        struct net_device *dev;
        char dev_name[IFNAMSIZ];
        const char *name;
        void (*rx_hook)(struct netpoll *, int, char *, int);
 
-       __be32 local_ip, remote_ip;
+       union inet_addr local_ip, remote_ip;
+       bool ipv6;
        u16 local_port, remote_port;
        u8 remote_mac[ETH_ALEN];
 
@@ -33,7 +42,7 @@ struct netpoll_info {
        spinlock_t rx_lock;
        struct list_head rx_np; /* netpolls that registered an rx_hook */
 
-       struct sk_buff_head arp_tx; /* list of arp requests to reply to */
+       struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */
        struct sk_buff_head txq;
 
        struct delayed_work tx_work;
index 93b3cf77f564e52b65a4fd19c248466e68298dcd..33999adbf8c85e91f16651c5d2dfd64ff2b58439 100644 (file)
@@ -506,13 +506,13 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45);
 int phy_device_register(struct phy_device *phy);
 int phy_init_hw(struct phy_device *phydev);
 struct phy_device * phy_attach(struct net_device *dev,
-               const char *bus_id, u32 flags, phy_interface_t interface);
+               const char *bus_id, phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
 int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
-               void (*handler)(struct net_device *), u32 flags,
+               void (*handler)(struct net_device *),
                phy_interface_t interface);
 struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
-               void (*handler)(struct net_device *), u32 flags,
+               void (*handler)(struct net_device *),
                phy_interface_t interface);
 void phy_disconnect(struct phy_device *phydev);
 void phy_detach(struct phy_device *phydev);
index d9846088c2c5fe63ed7b97c0c1a19a5bf23f31dc..347ce553a3065fd5020eb1ab864434db488df27c 100644 (file)
@@ -74,4 +74,10 @@ static inline int arch_get_random_int(unsigned int *v)
 }
 #endif
 
+/* Pseudo random number generator from numerical recipes. */
+static inline u32 next_pseudo_random32(u32 seed)
+{
+       return seed * 1664525 + 1013904223;
+}
+
 #endif /* _LINUX_RANDOM_H */
index 320e976d5ab861b9e143476ae7dcd4b87956854e..0259b719bebf504d6ab7001a36a68cdebe41dacd 100644 (file)
@@ -307,6 +307,13 @@ enum {
        SKB_GSO_TCPV6 = 1 << 4,
 
        SKB_GSO_FCOE = 1 << 5,
+
+       /* This indicates at least one fragment might be overwritten
+        * (as in vmsplice(), sendfile() ...)
+        * If we need to compute a TX checksum, we'll need to copy
+        * all frags to avoid possible bad checksum
+        */
+       SKB_GSO_SHARED_FRAG = 1 << 6,
 };
 
 #if BITS_PER_LONG > 32
@@ -1492,6 +1499,11 @@ static inline void skb_set_inner_network_header(struct sk_buff *skb,
        skb->inner_network_header += offset;
 }
 
+static inline bool skb_transport_header_was_set(const struct sk_buff *skb)
+{
+       return skb->transport_header != ~0U;
+}
+
 static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
 {
        return skb->head + skb->transport_header;
@@ -1580,6 +1592,11 @@ static inline void skb_set_inner_network_header(struct sk_buff *skb,
        skb->inner_network_header = skb->data + offset;
 }
 
+static inline bool skb_transport_header_was_set(const struct sk_buff *skb)
+{
+       return skb->transport_header != NULL;
+}
+
 static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
 {
        return skb->transport_header;
@@ -2190,6 +2207,18 @@ static inline int skb_linearize(struct sk_buff *skb)
        return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0;
 }
 
+/**
+ * skb_has_shared_frag - can any frag be overwritten
+ * @skb: buffer to test
+ *
+ * Return true if the skb has at least one frag that might be modified
+ * by an external entity (as in vmsplice()/sendfile())
+ */
+static inline bool skb_has_shared_frag(const struct sk_buff *skb)
+{
+       return skb_shinfo(skb)->gso_type & SKB_GSO_SHARED_FRAG;
+}
+
 /**
  *     skb_linearize_cow - make sure skb is linear and writable
  *     @skb: buffer to process
index c739531e156492e573e431d329fe058d6c56e9df..112c25c393a2e94c1c8a6c2339ce3849b50584aa 100644 (file)
@@ -91,7 +91,9 @@ struct tc_action_ops {
        int     (*dump)(struct sk_buff *, struct tc_action *, int, int);
        int     (*cleanup)(struct tc_action *, int bind);
        int     (*lookup)(struct tc_action *, u32);
-       int     (*init)(struct nlattr *, struct nlattr *, struct tc_action *, int , int);
+       int     (*init)(struct net *net, struct nlattr *nla,
+                       struct nlattr *est, struct tc_action *act, int ovr,
+                       int bind);
        int     (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *);
 };
 
@@ -116,8 +118,12 @@ extern int tcf_register_action(struct tc_action_ops *a);
 extern int tcf_unregister_action(struct tc_action_ops *a);
 extern void tcf_action_destroy(struct tc_action *a, int bind);
 extern int tcf_action_exec(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res);
-extern struct tc_action *tcf_action_init(struct nlattr *nla, struct nlattr *est, char *n, int ovr, int bind);
-extern struct tc_action *tcf_action_init_1(struct nlattr *nla, struct nlattr *est, char *n, int ovr, int bind);
+extern struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
+                                        struct nlattr *est, char *n, int ovr,
+                                        int bind);
+extern struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
+                                          struct nlattr *est, char *n, int ovr,
+                                          int bind);
 extern int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int);
 extern int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
 extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
index df4ef945338425d7fc6d64a858dd706d2628ea28..40be2a0d8ae1bef7270b06a8a04cc9b9ab30b630 100644 (file)
 
 #define IPV6_MAX_ADDRESSES             16
 
+#define ADDRCONF_TIMER_FUZZ_MINUS      (HZ > 50 ? HZ / 50 : 1)
+#define ADDRCONF_TIMER_FUZZ            (HZ / 4)
+#define ADDRCONF_TIMER_FUZZ_MAX                (HZ)
+
 #include <linux/in.h>
 #include <linux/in6.h>
 
@@ -150,7 +154,31 @@ extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
 extern bool ipv6_chk_mcast_addr(struct net_device *dev,
                                const struct in6_addr *group,
                                const struct in6_addr *src_addr);
-extern bool ipv6_is_mld(struct sk_buff *skb, int nexthdr);
+
+/*
+ * identify MLD packets for MLD filter exceptions
+ */
+static inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset)
+{
+       struct icmp6hdr *hdr;
+
+       if (nexthdr != IPPROTO_ICMPV6 ||
+           !pskb_network_may_pull(skb, offset + sizeof(struct icmp6hdr)))
+               return false;
+
+       hdr = (struct icmp6hdr *)(skb_network_header(skb) + offset);
+
+       switch (hdr->icmp6_type) {
+       case ICMPV6_MGM_QUERY:
+       case ICMPV6_MGM_REPORT:
+       case ICMPV6_MGM_REDUCTION:
+       case ICMPV6_MLD2_REPORT:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
 
 extern void addrconf_prefix_rcv(struct net_device *dev,
                                u8 *opt, int len, bool sllao);
@@ -257,30 +285,55 @@ static inline void addrconf_addr_solict_mult(const struct in6_addr *addr,
                      htonl(0xFF000000) | addr->s6_addr32[3]);
 }
 
-static inline int ipv6_addr_is_multicast(const struct in6_addr *addr)
+static inline bool ipv6_addr_is_multicast(const struct in6_addr *addr)
 {
        return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000);
 }
 
-static inline int ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
+static inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
 {
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       __u64 *p = (__u64 *)addr;
+       return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(1))) == 0UL;
+#else
        return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
                addr->s6_addr32[1] | addr->s6_addr32[2] |
                (addr->s6_addr32[3] ^ htonl(0x00000001))) == 0;
+#endif
 }
 
-static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
+static inline bool ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
 {
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       __u64 *p = (__u64 *)addr;
+       return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(2))) == 0UL;
+#else
        return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
                addr->s6_addr32[1] | addr->s6_addr32[2] |
                (addr->s6_addr32[3] ^ htonl(0x00000002))) == 0;
+#endif
 }
 
-static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
+static inline bool ipv6_addr_is_isatap(const struct in6_addr *addr)
 {
        return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
 }
 
+static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       __u64 *p = (__u64 *)addr;
+       return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) |
+               ((p[1] ^ cpu_to_be64(0x00000001ff000000UL)) &
+                cpu_to_be64(0xffffffffff000000UL))) == 0UL;
+#else
+       return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
+               addr->s6_addr32[1] |
+               (addr->s6_addr32[2] ^ htonl(0x00000001)) |
+               (addr->s6_addr[12] ^ 0xff)) == 0;
+#endif
+}
+
 #ifdef CONFIG_PROC_FS
 extern int if6_proc_init(void);
 extern void if6_proc_exit(void);
index 8e6a6b73b9c9ecc3f8f221c4ff32a9983940dde4..1b9830ebe6c6e49147e4ce91352805034c504105 100644 (file)
@@ -281,9 +281,13 @@ struct ieee80211_supported_band {
 /**
  * struct vif_params - describes virtual interface parameters
  * @use_4addr: use 4-address frames
+ * @macaddr: address to use for this virtual interface. This will only
+ *     be used for non-netdevice interfaces. If this parameter is set
+ *     to zero address the driver may determine the address as needed.
  */
 struct vif_params {
        int use_4addr;
+       u8 macaddr[ETH_ALEN];
 };
 
 /**
@@ -326,7 +330,7 @@ struct cfg80211_chan_def {
  * cfg80211_get_chandef_type - return old channel type from chandef
  * @chandef: the channel definition
  *
- * Returns the old channel type (NOHT, HT20, HT40+/-) from a given
+ * Return: The old channel type (NOHT, HT20, HT40+/-) from a given
  * chandef, which must have a bandwidth allowing this conversion.
  */
 static inline enum nl80211_channel_type
@@ -364,7 +368,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
  * @chandef1: first channel definition
  * @chandef2: second channel definition
  *
- * Returns %true if the channels defined by the channel definitions are
+ * Return: %true if the channels defined by the channel definitions are
  * identical, %false otherwise.
  */
 static inline bool
@@ -382,7 +386,7 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
  * @chandef1: first channel definition
  * @chandef2: second channel definition
  *
- * Returns %NULL if the given channel definitions are incompatible,
+ * Return: %NULL if the given channel definitions are incompatible,
  * chandef1 or chandef2 otherwise.
  */
 const struct cfg80211_chan_def *
@@ -392,6 +396,7 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
 /**
  * cfg80211_chandef_valid - check if a channel definition is valid
  * @chandef: the channel definition to check
+ * Return: %true if the channel definition is valid. %false otherwise.
  */
 bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef);
 
@@ -399,7 +404,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef);
  * cfg80211_chandef_usable - check if secondary channels can be used
  * @wiphy: the wiphy to validate against
  * @chandef: the channel definition to check
- * @prohibited_flags: the regulatory chanenl flags that must not be set
+ * @prohibited_flags: the regulatory channel flags that must not be set
+ * Return: %true if secondary channels are usable. %false otherwise.
  */
 bool cfg80211_chandef_usable(struct wiphy *wiphy,
                             const struct cfg80211_chan_def *chandef,
@@ -608,6 +614,8 @@ enum station_parameters_apply_mask {
  * @sta_modify_mask: bitmap indicating which parameters changed
  *     (for those that don't have a natural "no change" value),
  *     see &enum station_parameters_apply_mask
+ * @local_pm: local link-specific mesh power save mode (no change when set
+ *     to unknown)
  */
 struct station_parameters {
        u8 *supported_rates;
@@ -623,6 +631,7 @@ struct station_parameters {
        struct ieee80211_vht_cap *vht_capa;
        u8 uapsd_queues;
        u8 max_sp;
+       enum nl80211_mesh_power_mode local_pm;
 };
 
 /**
@@ -653,6 +662,9 @@ struct station_parameters {
  * @STATION_INFO_STA_FLAGS: @sta_flags filled
  * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled
  * @STATION_INFO_T_OFFSET: @t_offset filled
+ * @STATION_INFO_LOCAL_PM: @local_pm filled
+ * @STATION_INFO_PEER_PM: @peer_pm filled
+ * @STATION_INFO_NONPEER_PM: @nonpeer_pm filled
  */
 enum station_info_flags {
        STATION_INFO_INACTIVE_TIME      = 1<<0,
@@ -676,6 +688,9 @@ enum station_info_flags {
        STATION_INFO_STA_FLAGS          = 1<<18,
        STATION_INFO_BEACON_LOSS_COUNT  = 1<<19,
        STATION_INFO_T_OFFSET           = 1<<20,
+       STATION_INFO_LOCAL_PM           = 1<<21,
+       STATION_INFO_PEER_PM            = 1<<22,
+       STATION_INFO_NONPEER_PM         = 1<<23,
 };
 
 /**
@@ -789,6 +804,9 @@ struct sta_bss_parameters {
  * @sta_flags: station flags mask & values
  * @beacon_loss_count: Number of times beacon loss event has triggered.
  * @t_offset: Time offset of the station relative to this host.
+ * @local_pm: local mesh STA power save mode
+ * @peer_pm: peer mesh STA power save mode
+ * @nonpeer_pm: non-peer mesh STA power save mode
  */
 struct station_info {
        u32 filled;
@@ -818,6 +836,9 @@ struct station_info {
 
        u32 beacon_loss_count;
        s64 t_offset;
+       enum nl80211_mesh_power_mode local_pm;
+       enum nl80211_mesh_power_mode peer_pm;
+       enum nl80211_mesh_power_mode nonpeer_pm;
 
        /*
         * Note: Add a new enum station_info_flags value for each new field and
@@ -993,6 +1014,10 @@ struct bss_parameters {
  * @dot11MeshHWMPconfirmationInterval: The minimum interval of time (in TUs)
  *     during which a mesh STA can send only one Action frame containing
  *     a PREQ element for root path confirmation.
+ * @power_mode: The default mesh power save mode which will be the initial
+ *     setting for new peer links.
+ * @dot11MeshAwakeWindowDuration: The duration in TUs the STA will remain awake
+ *     after transmitting its beacon.
  */
 struct mesh_config {
        u16 dot11MeshRetryTimeout;
@@ -1020,6 +1045,8 @@ struct mesh_config {
        u32 dot11MeshHWMPactivePathToRootTimeout;
        u16 dot11MeshHWMProotInterval;
        u16 dot11MeshHWMPconfirmationInterval;
+       enum nl80211_mesh_power_mode power_mode;
+       u16 dot11MeshAwakeWindowDuration;
 };
 
 /**
@@ -1034,6 +1061,8 @@ struct mesh_config {
  * @ie_len: length of vendor information elements
  * @is_authenticated: this mesh requires authentication
  * @is_secure: this mesh uses security
+ * @dtim_period: DTIM period to use
+ * @beacon_interval: beacon interval to use
  * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
  *
  * These parameters are fixed when the mesh is created.
@@ -1049,6 +1078,8 @@ struct mesh_setup {
        u8 ie_len;
        bool is_authenticated;
        bool is_secure;
+       u8 dtim_period;
+       u16 beacon_interval;
        int mcast_rate[IEEE80211_NUM_BANDS];
 };
 
@@ -1256,7 +1287,7 @@ struct cfg80211_bss {
 
        u8 bssid[ETH_ALEN];
 
-       u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
+       u8 priv[0] __aligned(sizeof(void *));
 };
 
 /**
@@ -1266,7 +1297,7 @@ struct cfg80211_bss {
  *
  * Note that the return value is an RCU-protected pointer, so
  * rcu_read_lock() must be held when calling this function.
- * Returns %NULL if not found.
+ * Return: %NULL if not found.
  */
 const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
 
@@ -1434,6 +1465,7 @@ struct cfg80211_ibss_params {
  * @ie: IEs for association request
  * @ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
+ * @mfp: indicate whether management frame protection is used
  * @crypto: crypto settings
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
@@ -1454,6 +1486,7 @@ struct cfg80211_connect_params {
        u8 *ie;
        size_t ie_len;
        bool privacy;
+       enum nl80211_mfp mfp;
        struct cfg80211_crypto_settings crypto;
        const u8 *key;
        u8 key_len, key_idx;
@@ -2092,6 +2125,7 @@ struct ieee80211_iface_limit {
  * @beacon_int_infra_match: In this combination, the beacon intervals
  *     between infrastructure and AP types must match. This is required
  *     only in special cases.
+ * @radar_detect_widths: bitmap of channel widths supported for radar detection
  *
  * These examples can be expressed as follows:
  *
@@ -2144,6 +2178,7 @@ struct ieee80211_iface_combination {
        u16 max_interfaces;
        u8 n_limits;
        bool beacon_int_infra_match;
+       u8 radar_detect_widths;
 };
 
 struct mac_address {
@@ -2333,7 +2368,7 @@ struct wiphy {
        u32 rts_threshold;
        u8 coverage_class;
 
-       char fw_version[ETHTOOL_BUSINFO_LEN];
+       char fw_version[ETHTOOL_FWVERS_LEN];
        u32 hw_version;
 
 #ifdef CONFIG_PM
@@ -2364,12 +2399,12 @@ struct wiphy {
        struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
 
        /* Lets us get back the wiphy on the callback */
-       int (*reg_notifier)(struct wiphy *wiphy,
-                           struct regulatory_request *request);
+       void (*reg_notifier)(struct wiphy *wiphy,
+                            struct regulatory_request *request);
 
        /* fields below are read-only, assigned by cfg80211 */
 
-       const struct ieee80211_regdomain *regd;
+       const struct ieee80211_regdomain __rcu *regd;
 
        /* the item in /sys/class/ieee80211/ points to this,
         * you need use set_wiphy_dev() (see below) */
@@ -2392,7 +2427,7 @@ struct wiphy {
        const struct iw_handler_def *wext;
 #endif
 
-       char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
+       char priv[0] __aligned(NETDEV_ALIGN);
 };
 
 static inline struct net *wiphy_net(struct wiphy *wiphy)
@@ -2409,6 +2444,7 @@ static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
  * wiphy_priv - return priv from wiphy
  *
  * @wiphy: the wiphy whose priv pointer to return
+ * Return: The priv of @wiphy.
  */
 static inline void *wiphy_priv(struct wiphy *wiphy)
 {
@@ -2420,6 +2456,7 @@ static inline void *wiphy_priv(struct wiphy *wiphy)
  * priv_to_wiphy - return the wiphy containing the priv
  *
  * @priv: a pointer previously returned by wiphy_priv
+ * Return: The wiphy of @priv.
  */
 static inline struct wiphy *priv_to_wiphy(void *priv)
 {
@@ -2442,6 +2479,7 @@ static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev)
  * wiphy_dev - get wiphy dev pointer
  *
  * @wiphy: The wiphy whose device struct to look up
+ * Return: The dev of @wiphy.
  */
 static inline struct device *wiphy_dev(struct wiphy *wiphy)
 {
@@ -2452,6 +2490,7 @@ static inline struct device *wiphy_dev(struct wiphy *wiphy)
  * wiphy_name - get wiphy name
  *
  * @wiphy: The wiphy whose name to return
+ * Return: The name of @wiphy.
  */
 static inline const char *wiphy_name(const struct wiphy *wiphy)
 {
@@ -2467,8 +2506,8 @@ static inline const char *wiphy_name(const struct wiphy *wiphy)
  * Create a new wiphy and associate the given operations with it.
  * @sizeof_priv bytes are allocated for private use.
  *
- * The returned pointer must be assigned to each netdev's
- * ieee80211_ptr for proper operation.
+ * Return: A pointer to the new wiphy. This pointer must be
+ * assigned to each netdev's ieee80211_ptr for proper operation.
  */
 struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
 
@@ -2477,7 +2516,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
  *
  * @wiphy: The wiphy to register.
  *
- * Returns a non-negative wiphy index or a negative error code.
+ * Return: A non-negative wiphy index or a negative error code.
  */
 extern int wiphy_register(struct wiphy *wiphy);
 
@@ -2626,6 +2665,7 @@ static inline u8 *wdev_address(struct wireless_dev *wdev)
  * wdev_priv - return wiphy priv from wireless_dev
  *
  * @wdev: The wireless device whose wiphy's priv pointer to return
+ * Return: The wiphy priv of @wdev.
  */
 static inline void *wdev_priv(struct wireless_dev *wdev)
 {
@@ -2643,12 +2683,14 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
  * ieee80211_channel_to_frequency - convert channel number to frequency
  * @chan: channel number
  * @band: band, necessary due to channel number overlap
+ * Return: The corresponding frequency (in MHz), or 0 if the conversion failed.
  */
 extern int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band);
 
 /**
  * ieee80211_frequency_to_channel - convert frequency to channel number
  * @freq: center frequency
+ * Return: The corresponding channel, or 0 if the conversion failed.
  */
 extern int ieee80211_frequency_to_channel(int freq);
 
@@ -2665,6 +2707,7 @@ extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
  * ieee80211_get_channel - get channel struct from wiphy for specified frequency
  * @wiphy: the struct wiphy to get the channel for
  * @freq: the center frequency of the channel
+ * Return: The channel struct from @wiphy at @freq.
  */
 static inline struct ieee80211_channel *
 ieee80211_get_channel(struct wiphy *wiphy, int freq)
@@ -2679,10 +2722,10 @@ ieee80211_get_channel(struct wiphy *wiphy, int freq)
  * @basic_rates: bitmap of basic rates
  * @bitrate: the bitrate for which to find the basic rate
  *
- * This function returns the basic rate corresponding to a given
- * bitrate, that is the next lower bitrate contained in the basic
- * rate map, which is, for this function, given as a bitmap of
- * indices of rates in the band's bitrate table.
+ * Return: The basic rate corresponding to a given bitrate, that
+ * is the next lower bitrate contained in the basic rate map,
+ * which is, for this function, given as a bitmap of indices of
+ * rates in the band's bitrate table.
  */
 struct ieee80211_rate *
 ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
@@ -2775,18 +2818,21 @@ extern const unsigned char bridge_tunnel_header[6];
 /**
  * ieee80211_get_hdrlen_from_skb - get header length from data
  *
+ * @skb: the frame
+ *
  * Given an skb with a raw 802.11 header at the data pointer this function
- * returns the 802.11 header length in bytes (not including encryption
- * headers). If the data in the sk_buff is too short to contain a valid 802.11
- * header the function returns 0.
+ * returns the 802.11 header length.
  *
- * @skb: the frame
+ * Return: The 802.11 header length in bytes (not including encryption
+ * headers). Or 0 if the data in the sk_buff is too short to contain a valid
+ * 802.11 header.
  */
 unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
 
 /**
  * ieee80211_hdrlen - get header length in bytes from frame control
  * @fc: frame control field in little-endian format
+ * Return: The header length in bytes.
  */
 unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);
 
@@ -2794,7 +2840,7 @@ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);
  * ieee80211_get_mesh_hdrlen - get mesh extension header length
  * @meshhdr: the mesh extension header, only the flags field
  *     (first byte) will be accessed
- * Returns the length of the extension header, which is always at
+ * Return: The length of the extension header, which is always at
  * least 6 bytes and at most 18 if address 5 and 6 are present.
  */
 unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
@@ -2812,6 +2858,7 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
  * @skb: the 802.11 data frame
  * @addr: the device MAC address
  * @iftype: the virtual interface type
+ * Return: 0 on success. Non-zero on error.
  */
 int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                           enum nl80211_iftype iftype);
@@ -2823,6 +2870,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
  * @iftype: the virtual interface type
  * @bssid: the network bssid (used only for iftype STATION and ADHOC)
  * @qos: build 802.11 QoS data frame
+ * Return: 0 on success, or a negative error code.
  */
 int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                             enum nl80211_iftype iftype, u8 *bssid, bool qos);
@@ -2850,6 +2898,7 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 /**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
  * @skb: the data frame
+ * Return: The 802.1p/1d tag.
  */
 unsigned int cfg80211_classify8021d(struct sk_buff *skb);
 
@@ -2860,12 +2909,13 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb);
  * @ies: data consisting of IEs
  * @len: length of data
  *
- * This function will return %NULL if the element ID could
- * not be found or if the element is invalid (claims to be
- * longer than the given data), or a pointer to the first byte
- * of the requested element, that is the byte containing the
- * element ID. There are no checks on the element length
- * other than having to fit into the given data.
+ * Return: %NULL if the element ID could not be found or if
+ * the element is invalid (claims to be longer than the given
+ * data), or a pointer to the first byte of the requested
+ * element, that is the byte containing the element ID.
+ *
+ * Note: There are no checks on the element length other than
+ * having to fit into the given data.
  */
 const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
 
@@ -2877,12 +2927,13 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
  * @ies: data consisting of IEs
  * @len: length of data
  *
- * This function will return %NULL if the vendor specific element ID
- * could not be found or if the element is invalid (claims to be
- * longer than the given data), or a pointer to the first byte
- * of the requested element, that is the byte containing the
- * element ID. There are no checks on the element length
- * other than having to fit into the given data.
+ * Return: %NULL if the vendor specific element ID could not be found or if the
+ * element is invalid (claims to be longer than the given data), or a pointer to
+ * the first byte of the requested element, that is the byte containing the
+ * element ID.
+ *
+ * Note: There are no checks on the element length other than having to fit into
+ * the given data.
  */
 const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
                                  const u8 *ies, int len);
@@ -2915,6 +2966,8 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
  *
  * Drivers should check the return value, its possible you can get
  * an -ENOMEM.
+ *
+ * Return: 0 on success. -ENOMEM.
  */
 extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 
@@ -2938,28 +2991,22 @@ extern void wiphy_apply_custom_regulatory(
  * freq_reg_info - get regulatory information for the given frequency
  * @wiphy: the wiphy for which we want to process this rule for
  * @center_freq: Frequency in KHz for which we want regulatory information for
- * @desired_bw_khz: the desired max bandwidth you want to use per
- *     channel. Note that this is still 20 MHz if you want to use HT40
- *     as HT40 makes use of two channels for its 40 MHz width bandwidth.
- *     If set to 0 we'll assume you want the standard 20 MHz.
- * @reg_rule: the regulatory rule which we have for this frequency
  *
  * Use this function to get the regulatory rule for a specific frequency on
  * a given wireless device. If the device has a specific regulatory domain
  * it wants to follow we respect that unless a country IE has been received
  * and processed already.
  *
- * Returns 0 if it was able to find a valid regulatory rule which does
- * apply to the given center_freq otherwise it returns non-zero. It will
- * also return -ERANGE if we determine the given center_freq does not even have
- * a regulatory rule for a frequency range in the center_freq's band. See
- * freq_in_rule_band() for our current definition of a band -- this is purely
- * subjective and right now its 802.11 specific.
+ * Return: A valid pointer, or, when an error occurs, for example if no rule
+ * can be found, the return value is encoded using ERR_PTR(). Use IS_ERR() to
+ * check and PTR_ERR() to obtain the numeric return value. The numeric return
+ * value will be -ERANGE if we determine the given center_freq does not even
+ * have a regulatory rule for a frequency range in the center_freq's band.
+ * See freq_in_rule_band() for our current definition of a band -- this is
+ * purely subjective and right now it's 802.11 specific.
  */
-extern int freq_reg_info(struct wiphy *wiphy,
-                        u32 center_freq,
-                        u32 desired_bw_khz,
-                        const struct ieee80211_reg_rule **reg_rule);
+const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
+                                              u32 center_freq);
 
 /*
  * callbacks for asynchronous cfg80211 methods, notification
@@ -3006,7 +3053,8 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
  *
- * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
+ * Return: A referenced struct, must be released with cfg80211_put_bss()!
+ * Or %NULL on error.
  */
 struct cfg80211_bss * __must_check
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
@@ -3031,7 +3079,8 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
  *
- * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
+ * Return: A referenced struct, must be released with cfg80211_put_bss()!
+ * Or %NULL on error.
  */
 struct cfg80211_bss * __must_check
 cfg80211_inform_bss(struct wiphy *wiphy,
@@ -3308,16 +3357,18 @@ void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
  * the testmode command. Since it is intended for a reply, calling
  * it outside of the @testmode_cmd operation is invalid.
  *
- * The returned skb (or %NULL if any errors happen) is pre-filled
- * with the wiphy index and set up in a way that any data that is
- * put into the skb (with skb_put(), nla_put() or similar) will end
- * up being within the %NL80211_ATTR_TESTDATA attribute, so all that
- * needs to be done with the skb is adding data for the corresponding
- * userspace tool which can then read that data out of the testdata
- * attribute. You must not modify the skb in any other way.
+ * The returned skb is pre-filled with the wiphy index and set up in
+ * a way that any data that is put into the skb (with skb_put(),
+ * nla_put() or similar) will end up being within the
+ * %NL80211_ATTR_TESTDATA attribute, so all that needs to be done
+ * with the skb is adding data for the corresponding userspace tool
+ * which can then read that data out of the testdata attribute. You
+ * must not modify the skb in any other way.
  *
  * When done, call cfg80211_testmode_reply() with the skb and return
  * its error code as the result of the @testmode_cmd operation.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
  */
 struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
                                                  int approxlen);
@@ -3327,11 +3378,12 @@ struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
  * @skb: The skb, must have been allocated with
  *     cfg80211_testmode_alloc_reply_skb()
  *
- * Returns an error code or 0 on success, since calling this
- * function will usually be the last thing before returning
- * from the @testmode_cmd you should return the error code.
- * Note that this function consumes the skb regardless of the
- * return value.
+ * Since calling this function will usually be the last thing
+ * before returning from the @testmode_cmd you should return
+ * the error code.  Note that this function consumes the skb
+ * regardless of the return value.
+ *
+ * Return: An error code or 0 on success.
  */
 int cfg80211_testmode_reply(struct sk_buff *skb);
 
@@ -3345,14 +3397,16 @@ int cfg80211_testmode_reply(struct sk_buff *skb);
  * This function allocates and pre-fills an skb for an event on the
  * testmode multicast group.
  *
- * The returned skb (or %NULL if any errors happen) is set up in the
- * same way as with cfg80211_testmode_alloc_reply_skb() but prepared
- * for an event. As there, you should simply add data to it that will
- * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must
- * not modify the skb in any other way.
+ * The returned skb is set up in the same way as with
+ * cfg80211_testmode_alloc_reply_skb() but prepared for an event. As
+ * there, you should simply add data to it that will then end up in the
+ * %NL80211_ATTR_TESTDATA attribute. Again, you must not modify the skb
+ * in any other way.
  *
  * When done filling the skb, call cfg80211_testmode_event() with the
  * skb to send the event.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
  */
 struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
                                                  int approxlen, gfp_t gfp);
@@ -3533,13 +3587,13 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
  * @len: length of the frame data
  * @gfp: context flags
  *
- * Returns %true if a user space application has registered for this frame.
+ * This function is called whenever an Action frame is received for a station
+ * mode interface, but is not processed in kernel.
+ *
+ * Return: %true if a user space application has registered for this frame.
  * For action frames, that makes it responsible for rejecting unrecognized
  * action frames; %false otherwise, in which case for action frames the
  * driver is responsible for rejecting the frame.
- *
- * This function is called whenever an Action frame is received for a station
- * mode interface, but is not processed in kernel.
  */
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm,
                      const u8 *buf, size_t len, gfp_t gfp);
@@ -3631,7 +3685,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
  * This function is used in AP mode (only!) to inform userspace that
  * a spurious class 3 frame was received, to be able to deauth the
  * sender.
- * Returns %true if the frame was passed to userspace (or this failed
+ * Return: %true if the frame was passed to userspace (or this failed
  * for a reason other than not having a subscription.)
  */
 bool cfg80211_rx_spurious_frame(struct net_device *dev,
@@ -3647,7 +3701,7 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev,
  * an associated station sent a 4addr frame but that wasn't expected.
  * It is allowed and desirable to send this event only once for each
  * station to avoid event flooding.
- * Returns %true if the frame was passed to userspace (or this failed
+ * Return: %true if the frame was passed to userspace (or this failed
  * for a reason other than not having a subscription.)
  */
 bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
@@ -3685,8 +3739,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
  * @wiphy: the wiphy
  * @chandef: the channel definition
  *
- * This function returns true if there is no secondary channel or the secondary
- * channel(s) can be used for beaconing (i.e. is not a radar channel etc.)
+ * Return: %true if there is no secondary channel or the secondary channel(s)
+ * can be used for beaconing (i.e. is not a radar channel etc.)
  */
 bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
                             struct cfg80211_chan_def *chandef);
@@ -3756,9 +3810,9 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev);
  * The function finds a given P2P attribute in the (vendor) IEs and
  * copies its contents to the given buffer.
  *
- * The return value is a negative error code (-%EILSEQ or -%ENOENT) if
- * the data is malformed or the attribute can't be found (respectively),
- * or the length of the found attribute (which can be zero).
+ * Return: A negative error code (-%EILSEQ or -%ENOENT) if the data is
+ * malformed or the attribute can't be found (respectively), or the
+ * length of the found attribute (which can be zero).
  */
 int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
                          enum ieee80211_p2p_attr_id attr,
index 4f7d6a1823812f26554611359be5eef4264f34e0..2e9d317c82dcc7164ef9c3cfbfc8429c6364031a 100644 (file)
@@ -16,7 +16,7 @@
 *******************************************************************************/
 
 extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri);
-extern int dn_route_output_sock(struct dst_entry **pprt, struct flowidn *, struct sock *sk, int flags);
+extern int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *, struct sock *sk, int flags);
 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
 extern void dn_rt_cache_flush(int delay);
 
index 8a8d4e06900d8824ba4a892c5f29f9c40525f0e0..e1ad903a8d6a0ff2a93106a9a3e430d4f0089558 100644 (file)
@@ -43,11 +43,9 @@ static inline void ipv4_change_dsfield(struct iphdr *iph,__u8 mask,
 static inline void ipv6_change_dsfield(struct ipv6hdr *ipv6h,__u8 mask,
     __u8 value)
 {
-        __u16 tmp;
+       __be16 *p = (__force __be16 *)ipv6h;
 
-       tmp = ntohs(*(__be16 *) ipv6h);
-       tmp = (tmp & ((mask << 4) | 0xf00f)) | (value << 4);
-       *(__be16 *) ipv6h = htons(tmp);
+       *p = (*p & htons((((u16)mask << 4) | 0xf00f))) | htons((u16)value << 4);
 }
 
 
index e5062c955ea6594c3d7bd7850b76bce6a3640b5a..734d9b5f577a8036594251ced6e1af265fbc1c6a 100644 (file)
@@ -73,8 +73,8 @@ static inline int gro_cells_init(struct gro_cells *gcells, struct net_device *de
        int i;
 
        gcells->gro_cells_mask = roundup_pow_of_two(netif_get_num_default_rss_queues()) - 1;
-       gcells->cells = kcalloc(sizeof(struct gro_cell),
-                               gcells->gro_cells_mask + 1,
+       gcells->cells = kcalloc(gcells->gro_cells_mask + 1,
+                               sizeof(struct gro_cell),
                                GFP_KERNEL);
        if (!gcells->cells)
                return -ENOMEM;
index 9e34c877a77093ff1257e18941949a12391363d6..7ca75cbbf75e2071ed068276c8f69f1a11990b2a 100644 (file)
@@ -71,6 +71,8 @@ extern struct sock *__inet6_lookup_established(struct net *net,
 
 extern struct sock *inet6_lookup_listener(struct net *net,
                                          struct inet_hashinfo *hashinfo,
+                                         const struct in6_addr *saddr,
+                                         const __be16 sport,
                                          const struct in6_addr *daddr,
                                          const unsigned short hnum,
                                          const int dif);
@@ -88,7 +90,8 @@ static inline struct sock *__inet6_lookup(struct net *net,
        if (sk)
                return sk;
 
-       return inet6_lookup_listener(net, hashinfo, daddr, hnum, dif);
+       return inet6_lookup_listener(net, hashinfo, saddr, sport,
+                                    daddr, hnum, dif);
 }
 
 static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
index 32786a0447187f44e1264f4dc4c0b4721ebc3e08..3f237db0a426ce1606587da6060ce1da5f306b60 100644 (file)
@@ -1,10 +1,17 @@
 #ifndef __NET_FRAG_H__
 #define __NET_FRAG_H__
 
+#include <linux/percpu_counter.h>
+
 struct netns_frags {
        int                     nqueues;
-       atomic_t                mem;
        struct list_head        lru_list;
+       spinlock_t              lru_lock;
+
+       /* The percpu_counter "mem" need to be cacheline aligned.
+        *  mem.count must not share cacheline with other writers
+        */
+       struct percpu_counter   mem ____cacheline_aligned_in_smp;
 
        /* sysctls */
        int                     timeout;
@@ -13,12 +20,11 @@ struct netns_frags {
 };
 
 struct inet_frag_queue {
-       struct hlist_node       list;
-       struct netns_frags      *net;
-       struct list_head        lru_list;   /* lru list member */
        spinlock_t              lock;
-       atomic_t                refcnt;
        struct timer_list       timer;      /* when will this queue expire? */
+       struct list_head        lru_list;   /* lru list member */
+       struct hlist_node       list;
+       atomic_t                refcnt;
        struct sk_buff          *fragments; /* list of received fragments */
        struct sk_buff          *fragments_tail;
        ktime_t                 stamp;
@@ -31,24 +37,29 @@ struct inet_frag_queue {
 #define INET_FRAG_LAST_IN      1
 
        u16                     max_size;
+
+       struct netns_frags      *net;
 };
 
 #define INETFRAGS_HASHSZ               64
 
 struct inet_frags {
        struct hlist_head       hash[INETFRAGS_HASHSZ];
-       rwlock_t                lock;
-       u32                     rnd;
-       int                     qsize;
+       /* This rwlock is a global lock (seperate per IPv4, IPv6 and
+        * netfilter). Important to keep this on a seperate cacheline.
+        */
+       rwlock_t                lock ____cacheline_aligned_in_smp;
        int                     secret_interval;
        struct timer_list       secret_timer;
+       u32                     rnd;
+       int                     qsize;
 
        unsigned int            (*hashfn)(struct inet_frag_queue *);
+       bool                    (*match)(struct inet_frag_queue *q, void *arg);
        void                    (*constructor)(struct inet_frag_queue *q,
                                                void *arg);
        void                    (*destructor)(struct inet_frag_queue *);
        void                    (*skb_free)(struct sk_buff *);
-       bool                    (*match)(struct inet_frag_queue *q, void *arg);
        void                    (*frag_expire)(unsigned long data);
 };
 
@@ -72,4 +83,59 @@ static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f
                inet_frag_destroy(q, f, NULL);
 }
 
+/* Memory Tracking Functions. */
+
+/* The default percpu_counter batch size is not big enough to scale to
+ * fragmentation mem acct sizes.
+ * The mem size of a 64K fragment is approx:
+ *  (44 fragments * 2944 truesize) + frag_queue struct(200) = 129736 bytes
+ */
+static unsigned int frag_percpu_counter_batch = 130000;
+
+static inline int frag_mem_limit(struct netns_frags *nf)
+{
+       return percpu_counter_read(&nf->mem);
+}
+
+static inline void sub_frag_mem_limit(struct inet_frag_queue *q, int i)
+{
+       __percpu_counter_add(&q->net->mem, -i, frag_percpu_counter_batch);
+}
+
+static inline void add_frag_mem_limit(struct inet_frag_queue *q, int i)
+{
+       __percpu_counter_add(&q->net->mem, i, frag_percpu_counter_batch);
+}
+
+static inline void init_frag_mem_limit(struct netns_frags *nf)
+{
+       percpu_counter_init(&nf->mem, 0);
+}
+
+static inline int sum_frag_mem_limit(struct netns_frags *nf)
+{
+       return percpu_counter_sum_positive(&nf->mem);
+}
+
+static inline void inet_frag_lru_move(struct inet_frag_queue *q)
+{
+       spin_lock(&q->net->lru_lock);
+       list_move_tail(&q->lru_list, &q->net->lru_list);
+       spin_unlock(&q->net->lru_lock);
+}
+
+static inline void inet_frag_lru_del(struct inet_frag_queue *q)
+{
+       spin_lock(&q->net->lru_lock);
+       list_del(&q->lru_list);
+       spin_unlock(&q->net->lru_lock);
+}
+
+static inline void inet_frag_lru_add(struct netns_frags *nf,
+                                    struct inet_frag_queue *q)
+{
+       spin_lock(&nf->lru_lock);
+       list_add_tail(&q->lru_list, &nf->lru_list);
+       spin_unlock(&nf->lru_lock);
+}
 #endif
index 67a8fa098e3a2b0d456996f78af4ff845db4d079..7b2ae9d37076fb49c6aaa62f110318689d92dda8 100644 (file)
@@ -81,7 +81,9 @@ struct inet_bind_bucket {
        struct net              *ib_net;
 #endif
        unsigned short          port;
-       signed short            fastreuse;
+       signed char             fastreuse;
+       signed char             fastreuseport;
+       kuid_t                  fastuid;
        int                     num_owners;
        struct hlist_node       node;
        struct hlist_head       owners;
@@ -257,15 +259,19 @@ extern void inet_unhash(struct sock *sk);
 
 extern struct sock *__inet_lookup_listener(struct net *net,
                                           struct inet_hashinfo *hashinfo,
+                                          const __be32 saddr,
+                                          const __be16 sport,
                                           const __be32 daddr,
                                           const unsigned short hnum,
                                           const int dif);
 
 static inline struct sock *inet_lookup_listener(struct net *net,
                struct inet_hashinfo *hashinfo,
+               __be32 saddr, __be16 sport,
                __be32 daddr, __be16 dport, int dif)
 {
-       return __inet_lookup_listener(net, hashinfo, daddr, ntohs(dport), dif);
+       return __inet_lookup_listener(net, hashinfo, saddr, sport,
+                                     daddr, ntohs(dport), dif);
 }
 
 /* Socket demux engine toys. */
@@ -358,7 +364,8 @@ static inline struct sock *__inet_lookup(struct net *net,
        struct sock *sk = __inet_lookup_established(net, hashinfo,
                                saddr, sport, daddr, hnum, dif);
 
-       return sk ? : __inet_lookup_listener(net, hashinfo, daddr, hnum, dif);
+       return sk ? : __inet_lookup_listener(net, hashinfo, saddr, sport,
+                                            daddr, hnum, dif);
 }
 
 static inline struct sock *inet_lookup(struct net *net,
index 652d3d309357c8d587c313817c61261479c78e0e..7686e3f5033d8364da7aad69be58b86018af7589 100644 (file)
 #include <linux/ipv6.h>
 
 #ifndef _HAVE_ARCH_IPV6_CSUM
-
-static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
-                                         const struct in6_addr *daddr,
-                                         __u32 len, unsigned short proto,
-                                         __wsum csum)
-{
-
-       int carry;
-       __u32 ulen;
-       __u32 uproto;
-       __u32 sum = (__force u32)csum;
-
-       sum += (__force u32)saddr->s6_addr32[0];
-       carry = (sum < (__force u32)saddr->s6_addr32[0]);
-       sum += carry;
-
-       sum += (__force u32)saddr->s6_addr32[1];
-       carry = (sum < (__force u32)saddr->s6_addr32[1]);
-       sum += carry;
-
-       sum += (__force u32)saddr->s6_addr32[2];
-       carry = (sum < (__force u32)saddr->s6_addr32[2]);
-       sum += carry;
-
-       sum += (__force u32)saddr->s6_addr32[3];
-       carry = (sum < (__force u32)saddr->s6_addr32[3]);
-       sum += carry;
-
-       sum += (__force u32)daddr->s6_addr32[0];
-       carry = (sum < (__force u32)daddr->s6_addr32[0]);
-       sum += carry;
-
-       sum += (__force u32)daddr->s6_addr32[1];
-       carry = (sum < (__force u32)daddr->s6_addr32[1]);
-       sum += carry;
-
-       sum += (__force u32)daddr->s6_addr32[2];
-       carry = (sum < (__force u32)daddr->s6_addr32[2]);
-       sum += carry;
-
-       sum += (__force u32)daddr->s6_addr32[3];
-       carry = (sum < (__force u32)daddr->s6_addr32[3]);
-       sum += carry;
-
-       ulen = (__force u32)htonl((__u32) len);
-       sum += ulen;
-       carry = (sum < ulen);
-       sum += carry;
-
-       uproto = (__force u32)htonl(proto);
-       sum += uproto;
-       carry = (sum < uproto);
-       sum += carry;
-
-       return csum_fold((__force __wsum)sum);
-}
-
+__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+                       const struct in6_addr *daddr,
+                       __u32 len, unsigned short proto,
+                       __wsum csum);
 #endif
 
 static __inline__ __sum16 tcp_v6_check(int len,
@@ -126,4 +73,5 @@ static inline void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
        __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
 }
 
+int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto);
 #endif
index fdc48a94a063ae8ce746c501a477ab3471ab028e..6919a501f99efeceb2f24d59d6a0a4a47ade857c 100644 (file)
@@ -89,8 +89,6 @@ struct fib6_table;
 struct rt6_info {
        struct dst_entry                dst;
 
-       struct neighbour                *n;
-
        /*
         * Tail elements of dst_entry (__refcnt etc.)
         * and these elements (rarely used in hot path) are in
index 27d83183e615ef0029150d58858e7828a06e6921..260f83f16bcfb3e79f2572604fc373c1830e2310 100644 (file)
@@ -23,6 +23,7 @@ struct route_info {
 #include <net/sock.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/route.h>
 
 #define RT6_LOOKUP_F_IFACE             0x00000001
 #define RT6_LOOKUP_F_REACHABLE         0x00000002
@@ -102,7 +103,6 @@ extern struct rt6_info              *rt6_lookup(struct net *net,
                                            int oif, int flags);
 
 extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
-                                        struct neighbour *neigh,
                                         struct flowi6 *fl6);
 extern int icmp6_dst_gc(void);
 
@@ -194,4 +194,11 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
               skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
 }
 
+static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, struct in6_addr *dest)
+{
+       if (rt->rt6i_flags & RTF_GATEWAY)
+               return &rt->rt6i_gateway;
+       return dest;
+}
+
 #endif
index 5af66b26ebdd6379ce34ae1a914c3c71a2ce5f32..dc30b60975efd8eeafe72945f783133b22abc258 100644 (file)
@@ -288,12 +288,12 @@ static inline int ip6_frag_nqueues(struct net *net)
 
 static inline int ip6_frag_mem(struct net *net)
 {
-       return atomic_read(&net->ipv6.frags.mem);
+       return sum_frag_mem_limit(&net->ipv6.frags);
 }
 #endif
 
-#define IPV6_FRAG_HIGH_THRESH  (256 * 1024)    /* 262144 */
-#define IPV6_FRAG_LOW_THRESH   (192 * 1024)    /* 196608 */
+#define IPV6_FRAG_HIGH_THRESH  (4 * 1024*1024) /* 4194304 */
+#define IPV6_FRAG_LOW_THRESH   (3 * 1024*1024) /* 3145728 */
 #define IPV6_FRAG_TIMEOUT      (60 * HZ)       /* 60 seconds */
 
 extern int __ipv6_addr_type(const struct in6_addr *addr);
@@ -355,14 +355,32 @@ static inline void ipv6_addr_prefix(struct in6_addr *pfx,
                pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);
 }
 
+static inline void __ipv6_addr_set_half(__be32 *addr,
+                                       __be32 wh, __be32 wl)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+#if defined(__BIG_ENDIAN)
+       if (__builtin_constant_p(wh) && __builtin_constant_p(wl)) {
+               *(__force u64 *)addr = ((__force u64)(wh) << 32 | (__force u64)(wl));
+               return;
+       }
+#elif defined(__LITTLE_ENDIAN)
+       if (__builtin_constant_p(wl) && __builtin_constant_p(wh)) {
+               *(__force u64 *)addr = ((__force u64)(wl) << 32 | (__force u64)(wh));
+               return;
+       }
+#endif
+#endif
+       addr[0] = wh;
+       addr[1] = wl;
+}
+
 static inline void ipv6_addr_set(struct in6_addr *addr, 
                                     __be32 w1, __be32 w2,
                                     __be32 w3, __be32 w4)
 {
-       addr->s6_addr32[0] = w1;
-       addr->s6_addr32[1] = w2;
-       addr->s6_addr32[2] = w3;
-       addr->s6_addr32[3] = w4;
+       __ipv6_addr_set_half(&addr->s6_addr32[0], w1, w2);
+       __ipv6_addr_set_half(&addr->s6_addr32[2], w3, w4);
 }
 
 static inline bool ipv6_addr_equal(const struct in6_addr *a1,
@@ -381,9 +399,37 @@ static inline bool ipv6_addr_equal(const struct in6_addr *a1,
 #endif
 }
 
-static inline bool __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2,
-                                      unsigned int prefixlen)
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+static inline bool __ipv6_prefix_equal64_half(const __be64 *a1,
+                                             const __be64 *a2,
+                                             unsigned int len)
+{
+       if (len && ((*a1 ^ *a2) & cpu_to_be64((~0UL) << (64 - len))))
+               return false;
+       return true;
+}
+
+static inline bool ipv6_prefix_equal(const struct in6_addr *addr1,
+                                    const struct in6_addr *addr2,
+                                    unsigned int prefixlen)
+{
+       const __be64 *a1 = (const __be64 *)addr1;
+       const __be64 *a2 = (const __be64 *)addr2;
+
+       if (prefixlen >= 64) {
+               if (a1[0] ^ a2[0])
+                       return false;
+               return __ipv6_prefix_equal64_half(a1 + 1, a2 + 1, prefixlen - 64);
+       }
+       return __ipv6_prefix_equal64_half(a1, a2, prefixlen);
+}
+#else
+static inline bool ipv6_prefix_equal(const struct in6_addr *addr1,
+                                    const struct in6_addr *addr2,
+                                    unsigned int prefixlen)
 {
+       const __be32 *a1 = addr1->s6_addr32;
+       const __be32 *a2 = addr2->s6_addr32;
        unsigned int pdw, pbi;
 
        /* check complete u32 in prefix */
@@ -398,14 +444,7 @@ static inline bool __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2,
 
        return true;
 }
-
-static inline bool ipv6_prefix_equal(const struct in6_addr *a1,
-                                    const struct in6_addr *a2,
-                                    unsigned int prefixlen)
-{
-       return __ipv6_prefix_equal(a1->s6_addr32, a2->s6_addr32,
-                                  prefixlen);
-}
+#endif
 
 struct inet_frag_queue;
 
@@ -475,14 +514,25 @@ static inline u32 ipv6_addr_hash(const struct in6_addr *a)
 
 static inline bool ipv6_addr_loopback(const struct in6_addr *a)
 {
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       const unsigned long *ul = (const unsigned long *)a;
+
+       return (ul[0] | (ul[1] ^ cpu_to_be64(1))) == 0UL;
+#else
        return (a->s6_addr32[0] | a->s6_addr32[1] |
                a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0;
+#endif
 }
 
 static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
 {
-       return (a->s6_addr32[0] | a->s6_addr32[1] |
-                (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
+       return (
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+               *(__be64 *)a |
+#else
+               (a->s6_addr32[0] | a->s6_addr32[1]) |
+#endif
+               (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0UL;
 }
 
 /*
@@ -507,7 +557,7 @@ static inline void ipv6_addr_set_v4mapped(const __be32 addr,
  * find the first different bit between two addresses
  * length of address must be a multiple of 32bits
  */
-static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen)
+static inline int __ipv6_addr_diff32(const void *token1, const void *token2, int addrlen)
 {
        const __be32 *a1 = token1, *a2 = token2;
        int i;
@@ -539,6 +589,33 @@ static inline int __ipv6_addr_diff(const void *token1, const void *token2, int a
        return addrlen << 5;
 }
 
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+static inline int __ipv6_addr_diff64(const void *token1, const void *token2, int addrlen)
+{
+       const __be64 *a1 = token1, *a2 = token2;
+       int i;
+
+       addrlen >>= 3;
+
+       for (i = 0; i < addrlen; i++) {
+               __be64 xb = a1[i] ^ a2[i];
+               if (xb)
+                       return i * 64 + 63 - __fls(be64_to_cpu(xb));
+       }
+
+       return addrlen << 6;
+}
+#endif
+
+static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       if (__builtin_constant_p(addrlen) && !(addrlen & 7))
+               return __ipv6_addr_diff64(token1, token2, addrlen);
+#endif
+       return __ipv6_addr_diff32(token1, token2, addrlen);
+}
+
 static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2)
 {
        return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
@@ -546,6 +623,20 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
 
 extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
 
+/*
+ *     Header manipulation
+ */
+static inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass,
+                               __be32 flowlabel)
+{
+       *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel;
+}
+
+static inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr)
+{
+       return *(__be32 *)hdr & IPV6_FLOWINFO_MASK;
+}
+
 /*
  *     Prototypes exported by ipv6
  */
@@ -570,13 +661,6 @@ extern int                 ip6_xmit(struct sock *sk,
                                         struct ipv6_txoptions *opt,
                                         int tclass);
 
-extern int                     ip6_nd_hdr(struct sock *sk,
-                                          struct sk_buff *skb,
-                                          struct net_device *dev,
-                                          const struct in6_addr *saddr,
-                                          const struct in6_addr *daddr,
-                                          int proto, int len);
-
 extern int                     ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
 
 extern int                     ip6_append_data(struct sock *sk,
index ee50c5eba50c027aed710c7fded8616b9461b96a..3037f49e51c89fad2f9b5ae64679a3913912ddba 100644 (file)
@@ -173,7 +173,7 @@ struct ieee80211_chanctx_conf {
 
        u8 rx_chains_static, rx_chains_dynamic;
 
-       u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+       u8 drv_priv[0] __aligned(sizeof(void *));
 };
 
 /**
@@ -1059,7 +1059,7 @@ struct ieee80211_vif {
        u32 driver_flags;
 
        /* must be last */
-       u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+       u8 drv_priv[0] __aligned(sizeof(void *));
 };
 
 static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
@@ -1209,7 +1209,7 @@ struct ieee80211_sta {
        u8 max_sp;
 
        /* must be last */
-       u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+       u8 drv_priv[0] __aligned(sizeof(void *));
 };
 
 /**
@@ -1522,6 +1522,8 @@ struct ieee80211_hw {
  * structure can then access it via hw->priv. Note that mac802111 drivers should
  * not use wiphy_priv() to try to get their private driver structure as this
  * is already used internally by mac80211.
+ *
+ * Return: The mac80211 driver hw struct of @wiphy.
  */
 struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy);
 
@@ -2033,17 +2035,29 @@ enum ieee80211_filter_flags {
  * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer
  * might receive the addBA frame and send a delBA right away!
  *
- * @IEEE80211_AMPDU_RX_START: start Rx aggregation
- * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation
- * @IEEE80211_AMPDU_TX_START: start Tx aggregation
- * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
+ * @IEEE80211_AMPDU_RX_START: start RX aggregation
+ * @IEEE80211_AMPDU_RX_STOP: stop RX aggregation
+ * @IEEE80211_AMPDU_TX_START: start TX aggregation
  * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational
+ * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting
+ *     queued packets, now unaggregated. After all packets are transmitted the
+ *     driver has to call ieee80211_stop_tx_ba_cb_irqsafe().
+ * @IEEE80211_AMPDU_TX_STOP_FLUSH: stop TX aggregation and flush all packets,
+ *     called when the station is removed. There's no need or reason to call
+ *     ieee80211_stop_tx_ba_cb_irqsafe() in this case as mac80211 assumes the
+ *     session is gone and removes the station.
+ * @IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: called when TX aggregation is stopped
+ *     but the driver hasn't called ieee80211_stop_tx_ba_cb_irqsafe() yet and
+ *     now the connection is dropped and the station will be removed. Drivers
+ *     should clean up and drop remaining packets when this is called.
  */
 enum ieee80211_ampdu_mlme_action {
        IEEE80211_AMPDU_RX_START,
        IEEE80211_AMPDU_RX_STOP,
        IEEE80211_AMPDU_TX_START,
-       IEEE80211_AMPDU_TX_STOP,
+       IEEE80211_AMPDU_TX_STOP_CONT,
+       IEEE80211_AMPDU_TX_STOP_FLUSH,
+       IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
        IEEE80211_AMPDU_TX_OPERATIONAL,
 };
 
@@ -2474,7 +2488,10 @@ enum ieee80211_rate_control_changed {
  *
  * @restart_complete: Called after a call to ieee80211_restart_hw(), when the
  *     reconfiguration has completed. This can help the driver implement the
- *     reconfiguration step. This callback may sleep.
+ *     reconfiguration step. Also called when reconfiguring because the
+ *     driver's resume function returned 1, as this is just like an "inline"
+ *     hardware restart. This callback may sleep.
+ *
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -2661,6 +2678,8 @@ struct ieee80211_ops {
  *
  * @priv_data_len: length of private data
  * @ops: callbacks for this device
+ *
+ * Return: A pointer to the new hardware device, or %NULL on error.
  */
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops);
@@ -2673,6 +2692,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
  * need to fill the contained wiphy's information.
  *
  * @hw: the device to register as returned by ieee80211_alloc_hw()
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 int ieee80211_register_hw(struct ieee80211_hw *hw);
 
@@ -2719,6 +2740,8 @@ extern char *__ieee80211_create_tpt_led_trigger(
  * of the trigger so you can automatically link the LED device.
  *
  * @hw: the hardware to get the LED trigger name for
+ *
+ * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
 static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
 {
@@ -2738,6 +2761,8 @@ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
  * of the trigger so you can automatically link the LED device.
  *
  * @hw: the hardware to get the LED trigger name for
+ *
+ * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
 static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
 {
@@ -2757,6 +2782,8 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
  * of the trigger so you can automatically link the LED device.
  *
  * @hw: the hardware to get the LED trigger name for
+ *
+ * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
 static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 {
@@ -2776,6 +2803,8 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
  * of the trigger so you can automatically link the LED device.
  *
  * @hw: the hardware to get the LED trigger name for
+ *
+ * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
 static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
 {
@@ -2793,9 +2822,10 @@ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
  * @blink_table: the blink table -- needs to be ordered by throughput
  * @blink_table_len: size of the blink table
  *
- * This function returns %NULL (in case of error, or if no LED
- * triggers are configured) or the name of the new trigger.
- * This function must be called before ieee80211_register_hw().
+ * Return: %NULL (in case of error, or if no LED triggers are
+ * configured) or the name of the new trigger.
+ *
+ * Note: This function must be called before ieee80211_register_hw().
  */
 static inline char *
 ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, unsigned int flags,
@@ -2928,10 +2958,10 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw,
  * Calls to this function for a single hardware must be synchronized against
  * each other.
  *
- * The function returns -EINVAL when the requested PS mode is already set.
- *
  * @sta: currently connected sta
  * @start: start or stop PS
+ *
+ * Return: 0 on success. -EINVAL when the requested PS mode is already set.
  */
 int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start);
 
@@ -2945,6 +2975,8 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start);
  *
  * @sta: currently connected sta
  * @start: start or stop PS
+ *
+ * Return: Like ieee80211_sta_ps_transition().
  */
 static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
                                                  bool start)
@@ -3082,6 +3114,8 @@ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets);
  * according to the current DTIM parameters/TIM bitmap.
  *
  * The driver is responsible for freeing the returned skb.
+ *
+ * Return: The beacon template. %NULL on error.
  */
 struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                                         struct ieee80211_vif *vif,
@@ -3093,6 +3127,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * See ieee80211_beacon_get_tim().
+ *
+ * Return: See ieee80211_beacon_get_tim().
  */
 static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                                                   struct ieee80211_vif *vif)
@@ -3109,6 +3145,8 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
  * hardware. The destination address should be set by the caller.
  *
  * Can only be called in AP mode.
+ *
+ * Return: The Probe Response template. %NULL on error.
  */
 struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
                                        struct ieee80211_vif *vif);
@@ -3124,6 +3162,8 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
  *
  * Note: Caller (or hardware) is responsible for setting the
  * &IEEE80211_FCTL_PM bit.
+ *
+ * Return: The PS Poll template. %NULL on error.
  */
 struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif);
@@ -3139,6 +3179,8 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
  *
  * Note: Caller (or hardware) is responsible for setting the
  * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields.
+ *
+ * Return: The nullfunc template. %NULL on error.
  */
 struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif);
@@ -3153,6 +3195,8 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
  *
  * Creates a Probe Request template which can, for example, be uploaded to
  * hardware.
+ *
+ * Return: The Probe Request template. %NULL on error.
  */
 struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
@@ -3188,6 +3232,8 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  * If the RTS is generated in firmware, but the host system must provide
  * the duration field, the low-level driver uses this function to receive
  * the duration field value in little-endian byteorder.
+ *
+ * Return: The duration.
  */
 __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif, size_t frame_len,
@@ -3223,6 +3269,8 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
  * If the CTS-to-self is generated in firmware, but the host system must provide
  * the duration field, the low-level driver uses this function to receive
  * the duration field value in little-endian byteorder.
+ *
+ * Return: The duration.
  */
 __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
@@ -3239,6 +3287,8 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
  *
  * Calculate the duration field of some generic frame, given its
  * length and transmission rate (in 100kbps).
+ *
+ * Return: The duration.
  */
 __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
                                        struct ieee80211_vif *vif,
@@ -3255,9 +3305,10 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
  * hardware/firmware does not implement buffering of broadcast/multicast
  * frames when power saving is used, 802.11 code buffers them in the host
  * memory. The low-level driver uses this function to fetch next buffered
- * frame. In most cases, this is used when generating beacon frame. This
- * function returns a pointer to the next buffered skb or NULL if no more
- * buffered frames are available.
+ * frame. In most cases, this is used when generating beacon frame.
+ *
+ * Return: A pointer to the next buffered skb or NULL if no more buffered
+ * frames are available.
  *
  * Note: buffered frames are returned only after DTIM beacon frame was
  * generated with ieee80211_beacon_get() and the low-level driver must thus
@@ -3437,6 +3488,8 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
  * @queue: queue number (counted from zero).
  *
  * Drivers should use this function instead of netif_stop_queue.
+ *
+ * Return: %true if the queue is stopped. %false otherwise.
  */
 
 int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue);
@@ -3634,7 +3687,9 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
  * @vif: virtual interface to look for station on
  * @addr: station's address
  *
- * This function must be called under RCU lock and the
+ * Return: The station, if found. %NULL otherwise.
+ *
+ * Note: This function must be called under RCU lock and the
  * resulting pointer is only valid under RCU lock as well.
  */
 struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
@@ -3647,7 +3702,9 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
  * @addr: remote station's address
  * @localaddr: local address (vif->sdata->vif.addr). Use NULL for 'any'.
  *
- * This function must be called under RCU lock and the
+ * Return: The station, if found. %NULL otherwise.
+ *
+ * Note: This function must be called under RCU lock and the
  * resulting pointer is only valid under RCU lock as well.
  *
  * NOTE: You may pass NULL for localaddr, but then you will just get
@@ -3754,6 +3811,11 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
  * The iterator will not find a context that's being added (during
  * the driver callback to add it) but will find it while it's being
  * removed.
+ *
+ * Note that during hardware restart, all contexts that existed
+ * before the restart are considered already present so will be
+ * found while iterating, whether they've been re-added already
+ * or not.
  */
 void ieee80211_iter_chan_contexts_atomic(
        struct ieee80211_hw *hw,
@@ -3772,7 +3834,9 @@ void ieee80211_iter_chan_contexts_atomic(
  * information. This function must only be called from within the
  * .bss_info_changed callback function and only in managed mode. The function
  * is only useful when the interface is associated, otherwise it will return
- * NULL.
+ * %NULL.
+ *
+ * Return: The Probe Request template. %NULL on error.
  */
 struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
                                          struct ieee80211_vif *vif);
@@ -4119,12 +4183,14 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
 void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
 
 /**
- * ieee80211_ave_rssi - report the average rssi for the specified interface
+ * ieee80211_ave_rssi - report the average RSSI for the specified interface
  *
  * @vif: the specified virtual interface
  *
- * This function return the average rssi value for the requested interface.
- * It assumes that the given vif is valid.
+ * Note: This function assumes that the given vif is valid.
+ *
+ * Return: The average RSSI value for the requested interface, or 0 if not
+ * applicable.
  */
 int ieee80211_ave_rssi(struct ieee80211_vif *vif);
 
index 23b3a7c5878308003f2bd89c53f78703a20980e9..745bf741e029c50d8a464374ec5cc4bae855c655 100644 (file)
@@ -127,13 +127,19 @@ static int ndisc_addr_option_pad(unsigned short type)
        }
 }
 
+static inline int ndisc_opt_addr_space(struct net_device *dev)
+{
+       return NDISC_OPT_SPACE(dev->addr_len +
+                              ndisc_addr_option_pad(dev->type));
+}
+
 static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
                                      struct net_device *dev)
 {
        u8 *lladdr = (u8 *)(p + 1);
        int lladdrlen = p->nd_opt_len << 3;
        int prepad = ndisc_addr_option_pad(dev->type);
-       if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
+       if (lladdrlen != ndisc_opt_addr_space(dev))
                return NULL;
        return lladdr + prepad;
 }
@@ -148,15 +154,14 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _
                (p32[3] * hash_rnd[3]));
 }
 
-static inline struct neighbour *__ipv6_neigh_lookup(struct neigh_table *tbl, struct net_device *dev, const void *pkey)
+static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey)
 {
        struct neigh_hash_table *nht;
        const u32 *p32 = pkey;
        struct neighbour *n;
        u32 hash_val;
 
-       rcu_read_lock_bh();
-       nht = rcu_dereference_bh(tbl->nht);
+       nht = rcu_dereference_bh(nd_tbl.nht);
        hash_val = ndisc_hashfn(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
        for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
             n != NULL;
@@ -164,12 +169,21 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct neigh_table *tbl, str
                u32 *n32 = (u32 *) n->primary_key;
                if (n->dev == dev &&
                    ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) |
-                    (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0) {
-                       if (!atomic_inc_not_zero(&n->refcnt))
-                               n = NULL;
-                       break;
-               }
+                    (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0)
+                       return n;
        }
+
+       return NULL;
+}
+
+static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey)
+{
+       struct neighbour *n;
+
+       rcu_read_lock_bh();
+       n = __ipv6_neigh_lookup_noref(dev, pkey);
+       if (n && !atomic_inc_not_zero(&n->refcnt))
+               n = NULL;
        rcu_read_unlock_bh();
 
        return n;
index 0dab173e27da6e8e66a8eea4913f5b0230f612bd..629ee573c6d0307a4d394dcc16e9812e955a36d4 100644 (file)
@@ -184,7 +184,7 @@ struct neigh_table {
 
 static inline void *neighbour_priv(const struct neighbour *n)
 {
-       return (char *)n + ALIGN(sizeof(*n) + n->tbl->key_len, NEIGH_PRIV_ALIGN);
+       return (char *)n + n->tbl->entry_size;
 }
 
 /* flags for neigh_update() */
index 3ce4988c9c08a96c0837407bd7c092c043a0309b..fe630dde35c3f3688d30e1e33a5fb5d06393bba6 100644 (file)
@@ -16,9 +16,8 @@ struct neighbour;
 
 struct netevent_redirect {
        struct dst_entry *old;
-       struct neighbour *old_neigh;
        struct dst_entry *new;
-       struct neighbour *new_neigh;
+       struct neighbour *neigh;
        const void *daddr;
 };
 
index 463ae8e166965908d2fc0a60e92296123b846f2e..2bdb7a15fe06b102a5fc88c2cc3da5662ff53a95 100644 (file)
@@ -57,7 +57,9 @@ static inline void nf_ct_set_acct(struct net *net, bool enable)
        net->ct.sysctl_acct = enable;
 }
 
-extern int nf_conntrack_acct_init(struct net *net);
-extern void nf_conntrack_acct_fini(struct net *net);
+extern int nf_conntrack_acct_pernet_init(struct net *net);
+extern void nf_conntrack_acct_pernet_fini(struct net *net);
 
+extern int nf_conntrack_acct_init(void);
+extern void nf_conntrack_acct_fini(void);
 #endif /* _NF_CONNTRACK_ACCT_H */
index e98aeb3da033a38e29f745d5f043a33d3888bcc3..930275fa2ea68f082e5974586abc39c5138706c4 100644 (file)
@@ -25,12 +25,19 @@ extern unsigned int nf_conntrack_in(struct net *net,
                                    unsigned int hooknum,
                                    struct sk_buff *skb);
 
-extern int nf_conntrack_init(struct net *net);
-extern void nf_conntrack_cleanup(struct net *net);
+extern int nf_conntrack_init_net(struct net *net);
+extern void nf_conntrack_cleanup_net(struct net *net);
 
-extern int nf_conntrack_proto_init(struct net *net);
-extern void nf_conntrack_proto_fini(struct net *net);
+extern int nf_conntrack_proto_pernet_init(struct net *net);
+extern void nf_conntrack_proto_pernet_fini(struct net *net);
 
+extern int nf_conntrack_proto_init(void);
+extern void nf_conntrack_proto_fini(void);
+
+extern int nf_conntrack_init_start(void);
+extern void nf_conntrack_cleanup_start(void);
+
+extern void nf_conntrack_init_end(void);
 extern void nf_conntrack_cleanup_end(void);
 
 extern bool
index 5654d292efd4f0883f6051610f6144552f20cb61..092dc651689f81d85a6ae686c5d761aee006918d 100644 (file)
@@ -207,9 +207,11 @@ nf_ct_expect_event(enum ip_conntrack_expect_events event,
        nf_ct_expect_event_report(event, exp, 0, 0);
 }
 
-extern int nf_conntrack_ecache_init(struct net *net);
-extern void nf_conntrack_ecache_fini(struct net *net);
+extern int nf_conntrack_ecache_pernet_init(struct net *net);
+extern void nf_conntrack_ecache_pernet_fini(struct net *net);
 
+extern int nf_conntrack_ecache_init(void);
+extern void nf_conntrack_ecache_fini(void);
 #else /* CONFIG_NF_CONNTRACK_EVENTS */
 
 static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
@@ -232,12 +234,21 @@ static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e,
                                             u32 portid,
                                             int report) {}
 
-static inline int nf_conntrack_ecache_init(struct net *net)
+static inline int nf_conntrack_ecache_pernet_init(struct net *net)
 {
        return 0;
 }
 
-static inline void nf_conntrack_ecache_fini(struct net *net)
+static inline void nf_conntrack_ecache_pernet_fini(struct net *net)
+{
+}
+
+static inline int nf_conntrack_ecache_init(void)
+{
+       return 0;
+}
+
+static inline void nf_conntrack_ecache_fini(void)
 {
 }
 #endif /* CONFIG_NF_CONNTRACK_EVENTS */
index cc13f377a705c36c62987060d3cbe5e63eac8147..cbbae7621e229806bab08c8d622c599ea4db9364 100644 (file)
@@ -69,8 +69,11 @@ struct nf_conntrack_expect_policy {
 
 #define NF_CT_EXPECT_CLASS_DEFAULT     0
 
-int nf_conntrack_expect_init(struct net *net);
-void nf_conntrack_expect_fini(struct net *net);
+int nf_conntrack_expect_pernet_init(struct net *net);
+void nf_conntrack_expect_pernet_fini(struct net *net);
+
+int nf_conntrack_expect_init(void);
+void nf_conntrack_expect_fini(void);
 
 struct nf_conntrack_expect *
 __nf_ct_expect_find(struct net *net, u16 zone,
index 8b4d1fc29096b1d543241360d7832a32dcfb1904..977bc8a46444d12b960fd3646969a2e96ce064dd 100644 (file)
@@ -22,6 +22,9 @@ enum nf_ct_ext_id {
 #endif
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
        NF_CT_EXT_TIMEOUT,
+#endif
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       NF_CT_EXT_LABELS,
 #endif
        NF_CT_EXT_NUM,
 };
@@ -33,6 +36,7 @@ enum nf_ct_ext_id {
 #define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
 #define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp
 #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
+#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
 
 /* Extensions: optional stuff which isn't permanently in struct. */
 struct nf_ct_ext {
index 9aad956d1008e2be1c0b6e55b7588098321c642d..ce27edf57570e68db084630fa5cb86c1ba4bc880 100644 (file)
@@ -82,8 +82,11 @@ static inline void *nfct_help_data(const struct nf_conn *ct)
        return (void *)help->data;
 }
 
-extern int nf_conntrack_helper_init(struct net *net);
-extern void nf_conntrack_helper_fini(struct net *net);
+extern int nf_conntrack_helper_pernet_init(struct net *net);
+extern void nf_conntrack_helper_pernet_fini(struct net *net);
+
+extern int nf_conntrack_helper_init(void);
+extern void nf_conntrack_helper_fini(void);
 
 extern int nf_conntrack_broadcast_help(struct sk_buff *skb,
                                       unsigned int protoff,
index 6f7c13f4ac0329366ed32b9c5a27dc13253daff5..3bb89eac3fa130a477b925d87c441189d27836e1 100644 (file)
@@ -76,11 +76,16 @@ struct nf_conntrack_l3proto {
 
 extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX];
 
-/* Protocol registration. */
-extern int nf_conntrack_l3proto_register(struct net *net,
+/* Protocol pernet registration. */
+extern int nf_ct_l3proto_pernet_register(struct net *net,
                                         struct nf_conntrack_l3proto *proto);
-extern void nf_conntrack_l3proto_unregister(struct net *net,
+extern void nf_ct_l3proto_pernet_unregister(struct net *net,
                                            struct nf_conntrack_l3proto *proto);
+
+/* Protocol global registration. */
+extern int nf_ct_l3proto_register(struct nf_conntrack_l3proto *proto);
+extern void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto);
+
 extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto);
 extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
 
index c3be4aef6bf7d37055e521ca6f5dcf4468e8ae49..914d8d9007981bd9b4cf7db67dc79ec78c6896d0 100644 (file)
@@ -121,12 +121,16 @@ extern struct nf_conntrack_l4proto *
 nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto);
 extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p);
 
-/* Protocol registration. */
-extern int nf_conntrack_l4proto_register(struct net *net,
+/* Protocol pernet registration. */
+extern int nf_ct_l4proto_pernet_register(struct net *net,
                                         struct nf_conntrack_l4proto *proto);
-extern void nf_conntrack_l4proto_unregister(struct net *net,
+extern void nf_ct_l4proto_pernet_unregister(struct net *net,
                                            struct nf_conntrack_l4proto *proto);
 
+/* Protocol global registration. */
+extern int nf_ct_l4proto_register(struct nf_conntrack_l4proto *proto);
+extern void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *proto);
+
 static inline void nf_ct_kfree_compat_sysctl_table(struct nf_proto_net *pn)
 {
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
diff --git a/include/net/netfilter/nf_conntrack_labels.h b/include/net/netfilter/nf_conntrack_labels.h
new file mode 100644 (file)
index 0000000..c985695
--- /dev/null
@@ -0,0 +1,58 @@
+#include <linux/types.h>
+#include <net/net_namespace.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+#include <uapi/linux/netfilter/xt_connlabel.h>
+
+struct nf_conn_labels {
+       u8 words;
+       unsigned long bits[];
+};
+
+static inline struct nf_conn_labels *nf_ct_labels_find(const struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       return nf_ct_ext_find(ct, NF_CT_EXT_LABELS);
+#else
+       return NULL;
+#endif
+}
+
+static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       struct nf_conn_labels *cl_ext;
+       struct net *net = nf_ct_net(ct);
+       u8 words;
+
+       words = ACCESS_ONCE(net->ct.label_words);
+       if (words == 0 || WARN_ON_ONCE(words > 8))
+               return NULL;
+
+       cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS,
+                                     words * sizeof(long), GFP_ATOMIC);
+       if (cl_ext != NULL)
+               cl_ext->words = words;
+
+       return cl_ext;
+#else
+       return NULL;
+#endif
+}
+
+bool nf_connlabel_match(const struct nf_conn *ct, u16 bit);
+int nf_connlabel_set(struct nf_conn *ct, u16 bit);
+
+int nf_connlabels_replace(struct nf_conn *ct,
+                         const u32 *data, const u32 *mask, unsigned int words);
+
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+int nf_conntrack_labels_init(void);
+void nf_conntrack_labels_fini(void);
+#else
+static inline int nf_conntrack_labels_init(void) { return 0; }
+static inline void nf_conntrack_labels_fini(void) {}
+#endif
index e41e472d08f2123a7a0917e598196ec4ebf8e5d3..d23aceb16d9443a865bc0e789a60089b0d9c40bc 100644 (file)
@@ -76,15 +76,15 @@ nf_ct_timeout_lookup(struct net *net, struct nf_conn *ct,
 }
 
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
-extern int nf_conntrack_timeout_init(struct net *net);
-extern void nf_conntrack_timeout_fini(struct net *net);
+extern int nf_conntrack_timeout_init(void);
+extern void nf_conntrack_timeout_fini(void);
 #else
-static inline int nf_conntrack_timeout_init(struct net *net)
+static inline int nf_conntrack_timeout_init(void)
 {
         return 0;
 }
 
-static inline void nf_conntrack_timeout_fini(struct net *net)
+static inline void nf_conntrack_timeout_fini(void)
 {
         return;
 }
index fc9c82b1f06b1b484bbcdbe8ac0e52e615d2b42d..b00461413efd4d49ec3e11ba4a3e0786594a32f2 100644 (file)
@@ -48,15 +48,28 @@ static inline void nf_ct_set_tstamp(struct net *net, bool enable)
 }
 
 #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
-extern int nf_conntrack_tstamp_init(struct net *net);
-extern void nf_conntrack_tstamp_fini(struct net *net);
+extern int nf_conntrack_tstamp_pernet_init(struct net *net);
+extern void nf_conntrack_tstamp_pernet_fini(struct net *net);
+
+extern int nf_conntrack_tstamp_init(void);
+extern void nf_conntrack_tstamp_fini(void);
 #else
-static inline int nf_conntrack_tstamp_init(struct net *net)
+static inline int nf_conntrack_tstamp_pernet_init(struct net *net)
+{
+       return 0;
+}
+
+static inline void nf_conntrack_tstamp_pernet_fini(struct net *net)
+{
+       return;
+}
+
+static inline int nf_conntrack_tstamp_init(void)
 {
        return 0;
 }
 
-static inline void nf_conntrack_tstamp_fini(struct net *net)
+static inline void nf_conntrack_tstamp_fini(void)
 {
        return;
 }
index 75ca9291cf2ce307a8e54dec8a559a65069945f9..36d9379d4c4b495a20b65e448f3ecc4da5b3bf5e 100644 (file)
@@ -82,6 +82,7 @@ nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
                        break;
                case NFT_LOOKUP_LISTENER:
                        sk = inet_lookup_listener(net, &tcp_hashinfo,
+                                                   saddr, sport,
                                                    daddr, dport,
                                                    in->ifindex);
 
@@ -151,6 +152,7 @@ nf_tproxy_get_sock_v6(struct net *net, const u8 protocol,
                        break;
                case NFT_LOOKUP_LISTENER:
                        sk = inet6_lookup_listener(net, &tcp_hashinfo,
+                                                  saddr, sport,
                                                   daddr, ntohs(dport),
                                                   in->ifindex);
 
index 923cb20051edfbb93a3fb84c8c78b7dae0993c82..c9c0c538b68bb478c924e93d9b5408c933100459 100644 (file)
@@ -84,6 +84,10 @@ struct netns_ct {
        int                     sysctl_auto_assign_helper;
        bool                    auto_assign_helper_warned;
        struct nf_ip_net        nf_ct_proto;
+#if defined(CONFIG_NF_CONNTRACK_LABELS)
+       unsigned int            labels_used;
+       u8                      label_words;
+#endif
 #ifdef CONFIG_NF_NAT_NEEDED
        struct hlist_head       *nat_bysource;
        unsigned int            nat_htable_size;
index 2ae2b8372cfdc1a64210218fe3824d7f7973b60c..9b78862014a4c27609236b4ce9f73e69d682e7c7 100644 (file)
@@ -61,6 +61,8 @@ struct netns_ipv4 {
        int sysctl_icmp_ratemask;
        int sysctl_icmp_errors_use_inbound_ifaddr;
 
+       int sysctl_tcp_ecn;
+
        kgid_t sysctl_ping_group_range[2];
        long sysctl_tcp_mem[3];
 
index 671953e11575449b30a10081d5b7aa7b26c0fa0a..b87a1692b0864f436a9185447cbfe74cce6ec7e1 100644 (file)
@@ -57,8 +57,10 @@ struct nfc_hci_ops {
        int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_hci_dev *hdev,
                              struct nfc_target *target);
-       void (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
-                               struct sk_buff *skb);
+       int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+                             struct sk_buff *skb);
+       int (*enable_se)(struct nfc_dev *dev, u32 secure_element);
+       int (*disable_se)(struct nfc_dev *dev, u32 secure_element);
 };
 
 /* Pipes */
@@ -82,11 +84,23 @@ typedef int (*xmit) (struct sk_buff *skb, void *cb_data);
 
 #define NFC_HCI_MAX_GATES              256
 
+/*
+ * These values can be specified by a driver to indicate it requires some
+ * adaptation of the HCI standard.
+ *
+ * NFC_HCI_QUIRK_SHORT_CLEAR - send HCI_ADM_CLEAR_ALL_PIPE cmd with no params
+ */
+enum {
+       NFC_HCI_QUIRK_SHORT_CLEAR       = 0,
+};
+
 struct nfc_hci_dev {
        struct nfc_dev *ndev;
 
        u32 max_data_link_payload;
 
+       bool shutting_down;
+
        struct mutex msg_tx_mutex;
 
        struct list_head msg_tx_queue;
@@ -129,12 +143,16 @@ struct nfc_hci_dev {
 
        u8 *gb;
        size_t gb_len;
+
+       unsigned long quirks;
 };
 
 /* hci device allocation */
 struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
                                            struct nfc_hci_init_data *init_data,
+                                           unsigned long quirks,
                                            u32 protocols,
+                                           u32 supported_se,
                                            const char *llc_name,
                                            int tx_headroom,
                                            int tx_tailroom,
index d705d867494987b30da4272fe4c1967a7884412a..5bc0c460edc0189b56633a111159a15f7a430131 100644 (file)
@@ -147,6 +147,7 @@ struct nci_dev {
 /* ----- NCI Devices ----- */
 struct nci_dev *nci_allocate_device(struct nci_ops *ops,
                                    __u32 supported_protocols,
+                                   __u32 supported_se,
                                    int tx_headroom,
                                    int tx_tailroom);
 void nci_free_device(struct nci_dev *ndev);
index fce80b2f9be7e5eaf50e5fc5ccf55fde0440f793..87a6417fc934487acb2c734f53af3b78fb09d013 100644 (file)
@@ -68,6 +68,8 @@ struct nfc_ops {
                             void *cb_context);
        int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
+       int (*enable_se)(struct nfc_dev *dev, u32 secure_element);
+       int (*disable_se)(struct nfc_dev *dev, u32 secure_element);
 };
 
 #define NFC_TARGET_IDX_ANY -1
@@ -109,12 +111,17 @@ struct nfc_dev {
        struct nfc_genl_data genl_data;
        u32 supported_protocols;
 
+       u32 supported_se;
+       u32 active_se;
+
        int tx_headroom;
        int tx_tailroom;
 
        struct timer_list check_pres_timer;
        struct work_struct check_pres_work;
 
+       bool shutting_down;
+
        struct nfc_ops *ops;
 };
 #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
@@ -123,6 +130,7 @@ extern struct class nfc_class;
 
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
                                    u32 supported_protocols,
+                                   u32 supported_se,
                                    int tx_headroom,
                                    int tx_tailroom);
 
index 9fcc680ab6b9d1f4de4d15583275efe7acf66975..13174509cdfd38485a48f6fb1055f285a7306936 100644 (file)
@@ -126,9 +126,10 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
        return 0;
 }
 
-extern int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
-                            struct nlattr *rate_tlv, struct tcf_exts *exts,
-                            const struct tcf_ext_map *map);
+extern int tcf_exts_validate(struct net *net, struct tcf_proto *tp,
+                            struct nlattr **tb, struct nlattr *rate_tlv,
+                            struct tcf_exts *exts,
+                            const struct tcf_ext_map *map);
 extern void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts);
 extern void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
                             struct tcf_exts *src);
index 7dcaa2794fde2e5c753c49ce9fb7763cfd9d78e6..f17ed590d64a35b314c8c9c42dc7dc153e0f1619 100644 (file)
@@ -18,6 +18,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <linux/rcupdate.h>
 
 /**
  * enum environment_cap - Environment parsed from country IE
@@ -35,6 +36,7 @@ enum environment_cap {
 /**
  * struct regulatory_request - used to keep track of regulatory requests
  *
+ * @rcu_head: RCU head struct used to free the request
  * @wiphy_idx: this is set if this request's initiator is
  *     %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
  *     can be used by the wireless core to deal with conflicts
@@ -72,6 +74,7 @@ enum environment_cap {
  * @list: used to insert into the reg_requests_list linked list
  */
 struct regulatory_request {
+       struct rcu_head rcu_head;
        int wiphy_idx;
        enum nl80211_reg_initiator initiator;
        enum nl80211_user_reg_hint_type user_reg_hint_type;
@@ -101,6 +104,7 @@ struct ieee80211_reg_rule {
 };
 
 struct ieee80211_regdomain {
+       struct rcu_head rcu_head;
        u32 n_reg_rules;
        char alpha2[2];
        u8 dfs_region;
index 1540f9c2fcf4b555780087e48850911659009c25..2d06c2a53de176f3157b5487651de7f1d8c775e4 100644 (file)
@@ -195,7 +195,7 @@ struct tcf_proto_ops {
 
        unsigned long           (*get)(struct tcf_proto*, u32 handle);
        void                    (*put)(struct tcf_proto*, unsigned long);
-       int                     (*change)(struct sk_buff *,
+       int                     (*change)(struct net *net, struct sk_buff *,
                                        struct tcf_proto*, unsigned long,
                                        u32 handle, struct nlattr **,
                                        unsigned long *);
index 182ca99405adfb30e7b72181847b4a5ffd5d69ca..a340ab46b41cde493ad8cdeaef655f1b0ddf0397 100644 (file)
@@ -140,6 +140,7 @@ typedef __u64 __bitwise __addrpair;
  *     @skc_family: network address family
  *     @skc_state: Connection state
  *     @skc_reuse: %SO_REUSEADDR setting
+ *     @skc_reuseport: %SO_REUSEPORT setting
  *     @skc_bound_dev_if: bound device index if != 0
  *     @skc_bind_node: bind hash linkage for various protocol lookup tables
  *     @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol
@@ -179,7 +180,8 @@ struct sock_common {
 
        unsigned short          skc_family;
        volatile unsigned char  skc_state;
-       unsigned char           skc_reuse;
+       unsigned char           skc_reuse:4;
+       unsigned char           skc_reuseport:4;
        int                     skc_bound_dev_if;
        union {
                struct hlist_node       skc_bind_node;
@@ -297,6 +299,7 @@ struct sock {
 #define sk_family              __sk_common.skc_family
 #define sk_state               __sk_common.skc_state
 #define sk_reuse               __sk_common.skc_reuse
+#define sk_reuseport           __sk_common.skc_reuseport
 #define sk_bound_dev_if                __sk_common.skc_bound_dev_if
 #define sk_bind_node           __sk_common.skc_bind_node
 #define sk_prot                        __sk_common.skc_prot
@@ -337,7 +340,7 @@ struct sock {
 #endif
        unsigned long           sk_flags;
        struct dst_entry        *sk_rx_dst;
-       struct dst_entry        *sk_dst_cache;
+       struct dst_entry __rcu  *sk_dst_cache;
        spinlock_t              sk_dst_lock;
        atomic_t                sk_wmem_alloc;
        atomic_t                sk_omem_alloc;
@@ -664,6 +667,7 @@ enum sock_flags {
                     * Will use last 4 bytes of packet sent from
                     * user-space instead.
                     */
+       SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */
 };
 
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
index aed42c7851539ba945c562e7de8692e1201eee7c..614af8b7758e4ac31b4deec6134a9a95759a6533 100644 (file)
@@ -266,7 +266,6 @@ extern int sysctl_tcp_abort_on_overflow;
 extern int sysctl_tcp_max_orphans;
 extern int sysctl_tcp_fack;
 extern int sysctl_tcp_reordering;
-extern int sysctl_tcp_ecn;
 extern int sysctl_tcp_dsack;
 extern int sysctl_tcp_wmem[3];
 extern int sysctl_tcp_rmem[3];
@@ -504,7 +503,8 @@ static inline __u32 cookie_v4_init_sequence(struct sock *sk,
 #endif
 
 extern __u32 cookie_init_timestamp(struct request_sock *req);
-extern bool cookie_check_timestamp(struct tcp_options_received *opt, bool *);
+extern bool cookie_check_timestamp(struct tcp_options_received *opt,
+                               struct net *net, bool *ecn_ok);
 
 /* From net/ipv6/syncookies.c */
 extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
@@ -728,11 +728,12 @@ struct tcp_skb_cb {
  * notifications, we disable TCP ECN negociation.
  */
 static inline void
-TCP_ECN_create_request(struct request_sock *req, const struct sk_buff *skb)
+TCP_ECN_create_request(struct request_sock *req, const struct sk_buff *skb,
+               struct net *net)
 {
        const struct tcphdr *th = tcp_hdr(skb);
 
-       if (sysctl_tcp_ecn && th->ece && th->cwr &&
+       if (net->ipv4.sysctl_tcp_ecn && th->ece && th->cwr &&
            INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield))
                inet_rsk(req)->ecn_ok = 1;
 }
index 63445ede48bb7fd04b175c111935fb77464568b6..421f764794d59f5100ef3fe26190554a2e8a00c0 100644 (file)
@@ -557,10 +557,6 @@ struct xfrm_migrate {
 };
 
 #define XFRM_KM_TIMEOUT                30
-/* which seqno */
-#define XFRM_REPLAY_SEQ                1
-#define XFRM_REPLAY_OSEQ       2
-#define XFRM_REPLAY_SEQ_MASK   3
 /* what happened */
 #define XFRM_REPLAY_UPDATE     XFRM_AE_CR
 #define XFRM_REPLAY_TIMEOUT    XFRM_AE_CE
index 2d32d073a6f9e4275d47c27cbd63b169a3267b9a..4ef3acbba5daeba94e21ab2a9c4700c9b9cf2108 100644 (file)
@@ -22,8 +22,7 @@
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
-
+#define SO_REUSEPORT   15
 #ifndef SO_PASSCRED /* powerpc only differs in these */
 #define SO_PASSCRED    16
 #define SO_PEERCRED    17
@@ -73,4 +72,6 @@
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#define SO_LOCK_FILTER         44
+
 #endif /* __ASM_GENERIC_SOCKET_H */
index 8e1db18c3cb6d7091840be90c20289f19b81d724..ae07bec74f4bfb6d772c5d596ac08a06a1c28d35 100644 (file)
@@ -44,6 +44,7 @@ enum {
        CGW_SRC_IF,     /* ifindex of source network interface */
        CGW_DST_IF,     /* ifindex of destination network interface */
        CGW_FILTER,     /* specify struct can_filter on source CAN device */
+       CGW_DELETED,    /* number of deleted CAN frames (see max_hops param) */
        __CGW_MAX
 };
 
@@ -51,6 +52,7 @@ enum {
 
 #define CGW_FLAGS_CAN_ECHO 0x01
 #define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
+#define CGW_FLAGS_CAN_IIF_TX_OK 0x04
 
 #define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
 
index 60f3b6b906027e086f3c5a0e6ab4ef0ffa6daaf0..c4edfe11f1f7ed07092d085f28d49934a58f4903 100644 (file)
@@ -142,6 +142,7 @@ enum {
 #define IFLA_PROMISCUITY IFLA_PROMISCUITY
        IFLA_NUM_TX_QUEUES,
        IFLA_NUM_RX_QUEUES,
+       IFLA_CARRIER,
        __IFLA_MAX
 };
 
index f79c3721da6e772991779c4ee55eddce00f3bab0..53b1d56a6e7f3544b1cd3ec3bcac87b62e630c40 100644 (file)
@@ -38,11 +38,6 @@ struct in6_addr {
 #define s6_addr32              in6_u.u6_addr32
 };
 
-/* IPv6 Wildcard Address (::) and Loopback Address (::1) defined in RFC2553
- * NOTE: Be aware the IN6ADDR_* constants and in6addr_* externals are defined
- * in network byte order, not in host byte order as are the IPv4 equivalents
- */
-
 struct sockaddr_in6 {
        unsigned short int      sin6_family;    /* AF_INET6 */
        __be16                  sin6_port;      /* Transport layer port # */
@@ -264,17 +259,10 @@ struct in6_flowlabel_req {
 
 /*
  * Multicast Routing:
- * see include/linux/mroute6.h.
+ * see include/uapi/linux/mroute6.h.
  *
- * MRT6_INIT                   200
- * MRT6_DONE                   201
- * MRT6_ADD_MIF                        202
- * MRT6_DEL_MIF                        203
- * MRT6_ADD_MFC                        204
- * MRT6_DEL_MFC                        205
- * MRT6_VERSION                        206
- * MRT6_ASSERT                 207
- * MRT6_PIM                    208
- * (reserved)                  209
+ * MRT6_BASE                   200
+ * ...
+ * MRT6_MAX
  */
 #endif /* _UAPI_LINUX_IN6_H */
index 5a2991cf0251d558c15d108d9ea88155240425e7..4bda4cf5b0f56d84651497df86bd9fa09909fa85 100644 (file)
@@ -63,6 +63,8 @@ struct ipv6_opt_hdr {
 #define ipv6_destopt_hdr ipv6_opt_hdr
 #define ipv6_hopopt_hdr  ipv6_opt_hdr
 
+/* Router Alert option values (RFC2711) */
+#define IPV6_OPT_ROUTERALERT_MLD       0x0000  /* MLD(RFC2710) */
 
 /*
  *     routing header type 0 (used in cmsghdr struct)
index 16929993acc4976535c73bf8172e29789275bfeb..a382d2c04a42d061f758faa84f4b76820f135e48 100644 (file)
@@ -26,6 +26,9 @@
 #define MRT_ASSERT     (MRT_BASE+7)    /* Activate PIM assert mode             */
 #define MRT_PIM                (MRT_BASE+8)    /* enable PIM code                      */
 #define MRT_TABLE      (MRT_BASE+9)    /* Specify mroute table ID              */
+#define MRT_ADD_MFC_PROXY      (MRT_BASE+10)   /* Add a (*,*|G) mfc entry      */
+#define MRT_DEL_MFC_PROXY      (MRT_BASE+11)   /* Del a (*,*|G) mfc entry      */
+#define MRT_MAX                (MRT_BASE+11)
 
 #define SIOCGETVIFCNT  SIOCPROTOPRIVATE        /* IP protocol privates */
 #define SIOCGETSGCNT   (SIOCPROTOPRIVATE+1)
index 3e89b5e7f9e33052adeb6b5dafa01944f02ee5cc..ce91215cf7e62cab5832264edaf78f76b08a8205 100644 (file)
@@ -26,6 +26,9 @@
 #define MRT6_ASSERT    (MRT6_BASE+7)   /* Activate PIM assert mode             */
 #define MRT6_PIM       (MRT6_BASE+8)   /* enable PIM code                      */
 #define MRT6_TABLE     (MRT6_BASE+9)   /* Specify mroute table ID              */
+#define MRT6_ADD_MFC_PROXY     (MRT6_BASE+10)  /* Add a (*,*|G) mfc entry      */
+#define MRT6_DEL_MFC_PROXY     (MRT6_BASE+11)  /* Del a (*,*|G) mfc entry      */
+#define MRT6_MAX       (MRT6_BASE+11)
 
 #define SIOCGETMIFCNT_IN6      SIOCPROTOPRIVATE        /* IP protocol privates */
 #define SIOCGETSGCNT_IN6       (SIOCPROTOPRIVATE+1)
index 08f555fef13fee2946951983ae7cf2e210aa05cc..41115776d76f74996a0815e044533fc5e5ee8f78 100644 (file)
@@ -35,9 +35,11 @@ header-y += xt_TCPOPTSTRIP.h
 header-y += xt_TEE.h
 header-y += xt_TPROXY.h
 header-y += xt_addrtype.h
+header-y += xt_bpf.h
 header-y += xt_cluster.h
 header-y += xt_comment.h
 header-y += xt_connbytes.h
+header-y += xt_connlabel.h
 header-y += xt_connlimit.h
 header-y += xt_connmark.h
 header-y += xt_conntrack.h
index 1644cdd8be9109abc11a338451f1a9655e32cc1a..d69483fb382537e39c99251f5d3f580bf8115b62 100644 (file)
@@ -101,6 +101,7 @@ enum ip_conntrack_events {
        IPCT_MARK,              /* new mark has been set */
        IPCT_NATSEQADJ,         /* NAT is doing sequence adjustment */
        IPCT_SECMARK,           /* new security mark has been set */
+       IPCT_LABEL,             /* new connlabel has been set */
 };
 
 enum ip_conntrack_expect_events {
index 86e930cf3dfba3f472046e8cded054a1159a83d8..08fabc6c93f3ae6d7fb7ae1f8e443b288a93d952 100644 (file)
@@ -49,6 +49,8 @@ enum ctattr_type {
        CTA_SECCTX,
        CTA_TIMESTAMP,
        CTA_MARK_MASK,
+       CTA_LABELS,
+       CTA_LABELS_MASK,
        __CTA_MAX
 };
 #define CTA_MAX (__CTA_MAX - 1)
diff --git a/include/uapi/linux/netfilter/xt_bpf.h b/include/uapi/linux/netfilter/xt_bpf.h
new file mode 100644 (file)
index 0000000..5dda450
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _XT_BPF_H
+#define _XT_BPF_H
+
+#include <linux/filter.h>
+#include <linux/types.h>
+
+#define XT_BPF_MAX_NUM_INSTR   64
+
+struct xt_bpf_info {
+       __u16 bpf_program_num_elem;
+       struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR];
+
+       /* only used in the kernel */
+       struct sk_filter *filter __attribute__((aligned(8)));
+};
+
+#endif /*_XT_BPF_H */
diff --git a/include/uapi/linux/netfilter/xt_connlabel.h b/include/uapi/linux/netfilter/xt_connlabel.h
new file mode 100644 (file)
index 0000000..c4bc9ee
--- /dev/null
@@ -0,0 +1,12 @@
+#include <linux/types.h>
+
+#define XT_CONNLABEL_MAXBIT 127
+enum xt_connlabel_mtopts {
+       XT_CONNLABEL_OP_INVERT = 1 << 0,
+       XT_CONNLABEL_OP_SET    = 1 << 1,
+};
+
+struct xt_connlabel_mtinfo {
+       __u16 bit;
+       __u16 options;
+};
index 0e63cee8d810b7ef33832d6f030e4c2dbe246c63..7969f46f1bb344f55d704ae06b5bcdc609b07b85 100644 (file)
@@ -5,20 +5,17 @@
  *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
  *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #ifndef __LINUX_NFC_H
  *     subsequent CONNECT and CC messages.
  *     If one of the passed parameters is wrong none is set and -EINVAL is
  *     returned.
+ * @NFC_CMD_ENABLE_SE: Enable the physical link to a specific secure element.
+ *     Once enabled a secure element will handle card emulation mode, i.e.
+ *     starting a poll from a device which has a secure element enabled means
+ *     we want to do SE based card emulation.
+ * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element.
  */
 enum nfc_commands {
        NFC_CMD_UNSPEC,
@@ -86,6 +88,8 @@ enum nfc_commands {
        NFC_EVENT_TM_DEACTIVATED,
        NFC_CMD_LLC_GET_PARAMS,
        NFC_CMD_LLC_SET_PARAMS,
+       NFC_CMD_ENABLE_SE,
+       NFC_CMD_DISABLE_SE,
 /* private: internal use only */
        __NFC_CMD_AFTER_LAST
 };
@@ -114,6 +118,7 @@ enum nfc_commands {
  * @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter
  * @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter
  * @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter
+ * @NFC_ATTR_SE: Available Secure Elements
  */
 enum nfc_attrs {
        NFC_ATTR_UNSPEC,
@@ -134,6 +139,7 @@ enum nfc_attrs {
        NFC_ATTR_LLC_PARAM_LTO,
        NFC_ATTR_LLC_PARAM_RW,
        NFC_ATTR_LLC_PARAM_MIUX,
+       NFC_ATTR_SE,
 /* private: internal use only */
        __NFC_ATTR_AFTER_LAST
 };
@@ -172,6 +178,11 @@ enum nfc_attrs {
 #define NFC_PROTO_NFC_DEP_MASK   (1 << NFC_PROTO_NFC_DEP)
 #define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B)
 
+/* NFC Secure Elements */
+#define NFC_SE_NONE     0x0
+#define NFC_SE_UICC     0x1
+#define NFC_SE_EMBEDDED 0x2
+
 struct sockaddr_nfc {
        sa_family_t sa_family;
        __u32 dev_idx;
index e3e19f8b16f2de81107fd672476e6496632c8524..e6eeb4ba5dc58c83ce20c7773a1f20819e883d36 100644 (file)
  *     requests to connect to a specified network but without separating
  *     auth and assoc steps. For this, you need to specify the SSID in a
  *     %NL80211_ATTR_SSID attribute, and can optionally specify the association
- *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- *     %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
+ *     %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
  *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
  *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
  *     Background scan period can optionally be
@@ -958,7 +958,7 @@ enum nl80211_commands {
  * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
  *     used for the association (&enum nl80211_mfp, represented as a u32);
  *     this attribute can be used
- *     with %NL80211_CMD_ASSOCIATE request
+ *     with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
  *
  * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
  *     &struct nl80211_sta_flag_update.
@@ -1310,6 +1310,9 @@ enum nl80211_commands {
  *     if not given in START_AP 0 is assumed, if not given in SET_BSS
  *     no change is made.
  *
+ * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
+ *     defined in &enum nl80211_mesh_power_mode.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1580,6 +1583,8 @@ enum nl80211_attrs {
        NL80211_ATTR_P2P_CTWINDOW,
        NL80211_ATTR_P2P_OPPPS,
 
+       NL80211_ATTR_LOCAL_MESH_POWER_MODE,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1697,6 +1702,9 @@ enum nl80211_iftype {
  *     flag can't be changed, it is only valid while adding a station, and
  *     attempts to change it will silently be ignored (rather than rejected
  *     as errors.)
+ * @NL80211_STA_FLAG_ASSOCIATED: station is associated; used with drivers
+ *     that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a
+ *     previously added station into associated state
  * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
  * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
@@ -1708,6 +1716,7 @@ enum nl80211_sta_flags {
        NL80211_STA_FLAG_MFP,
        NL80211_STA_FLAG_AUTHENTICATED,
        NL80211_STA_FLAG_TDLS_PEER,
+       NL80211_STA_FLAG_ASSOCIATED,
 
        /* keep last */
        __NL80211_STA_FLAG_AFTER_LAST,
@@ -1834,6 +1843,10 @@ enum nl80211_sta_bss_param {
  * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
  * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
  * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
+ * @NL80211_STA_INFO_LOCAL_PM: local mesh STA link-specific power mode
+ * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
+ * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
+ *     non-peer STA
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -1858,6 +1871,9 @@ enum nl80211_sta_info {
        NL80211_STA_INFO_STA_FLAGS,
        NL80211_STA_INFO_BEACON_LOSS,
        NL80211_STA_INFO_T_OFFSET,
+       NL80211_STA_INFO_LOCAL_PM,
+       NL80211_STA_INFO_PEER_PM,
+       NL80211_STA_INFO_NONPEER_PM,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
@@ -2248,6 +2264,34 @@ enum nl80211_mntr_flags {
        NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_mesh_power_mode - mesh power save modes
+ *
+ * @NL80211_MESH_POWER_UNKNOWN: The mesh power mode of the mesh STA is
+ *     not known or has not been set yet.
+ * @NL80211_MESH_POWER_ACTIVE: Active mesh power mode. The mesh STA is
+ *     in Awake state all the time.
+ * @NL80211_MESH_POWER_LIGHT_SLEEP: Light sleep mode. The mesh STA will
+ *     alternate between Active and Doze states, but will wake up for
+ *     neighbor's beacons.
+ * @NL80211_MESH_POWER_DEEP_SLEEP: Deep sleep mode. The mesh STA will
+ *     alternate between Active and Doze states, but may not wake up
+ *     for neighbor's beacons.
+ *
+ * @__NL80211_MESH_POWER_AFTER_LAST - internal use
+ * @NL80211_MESH_POWER_MAX - highest possible power save level
+ */
+
+enum nl80211_mesh_power_mode {
+       NL80211_MESH_POWER_UNKNOWN,
+       NL80211_MESH_POWER_ACTIVE,
+       NL80211_MESH_POWER_LIGHT_SLEEP,
+       NL80211_MESH_POWER_DEEP_SLEEP,
+
+       __NL80211_MESH_POWER_AFTER_LAST,
+       NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
+};
+
 /**
  * enum nl80211_meshconf_params - mesh configuration parameters
  *
@@ -2342,6 +2386,11 @@ enum nl80211_mntr_flags {
  *     (in TUs) during which a mesh STA can send only one Action frame
  *     containing a PREQ element for root path confirmation.
  *
+ * @NL80211_MESHCONF_POWER_MODE: Default mesh power mode for new peer links.
+ *     type &enum nl80211_mesh_power_mode (u32)
+ *
+ * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2371,6 +2420,8 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
        NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
        NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+       NL80211_MESHCONF_POWER_MODE,
+       NL80211_MESHCONF_AWAKE_WINDOW,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2933,6 +2984,8 @@ enum nl80211_iface_limit_attrs {
  *     the infrastructure network's beacon interval.
  * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
  *     different channels may be used within this group.
+ * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap
+ *     of supported channel widths for radar detection.
  * @NUM_NL80211_IFACE_COMB: number of attributes
  * @MAX_NL80211_IFACE_COMB: highest attribute number
  *
@@ -2965,6 +3018,7 @@ enum nl80211_if_combination_attrs {
        NL80211_IFACE_COMB_MAXNUM,
        NL80211_IFACE_COMB_STA_AP_BI_MATCH,
        NL80211_IFACE_COMB_NUM_CHANNELS,
+       NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
 
        /* keep last */
        NUM_NL80211_IFACE_COMB,
@@ -3140,6 +3194,17 @@ enum nl80211_ap_sme_features {
  *     setting
  * @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic
  *     powersave
+ * @NL80211_FEATURE_FULL_AP_CLIENT_STATE: The driver supports full state
+ *     transitions for AP clients. Without this flag (and if the driver
+ *     doesn't have the AP SME in the device) the driver supports adding
+ *     stations only when they're associated and adds them in associated
+ *     state (to later be transitioned into authorized), with this flag
+ *     they should be added before even sending the authentication reply
+ *     and then transitioned into authenticated, associated and authorized
+ *     states using station flags.
+ *     Note that even for drivers that support this, the default is to add
+ *     stations in authenticated/associated state, so to add unauthenticated
+ *     stations the authenticated/associated bits have to be set in the mask.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -3155,6 +3220,7 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_NEED_OBSS_SCAN                  = 1 << 10,
        NL80211_FEATURE_P2P_GO_CTWIN                    = 1 << 11,
        NL80211_FEATURE_P2P_GO_OPPPS                    = 1 << 12,
+       NL80211_FEATURE_FULL_AP_CLIENT_STATE            = 1 << 13,
 };
 
 /**
index fdfba235f9f1a9bb6b8fc03958ae1982404dd125..b49eab89c9fd4461c155ec1b60083aeab1234e44 100644 (file)
@@ -278,6 +278,7 @@ enum
        LINUX_MIB_XFRMOUTPOLDEAD,               /* XfrmOutPolDead */
        LINUX_MIB_XFRMOUTPOLERROR,              /* XfrmOutPolError */
        LINUX_MIB_XFRMFWDHDRERROR,              /* XfrmFwdHdrError*/
+       LINUX_MIB_XFRMOUTSTATEINVALID,          /* XfrmOutStateInvalid */
        __LINUX_MIB_XFRMMAX
 };
 
index 848e3584d7c8063759548eb4f440e7b2bf262126..a5a8c88753b9579e8bcc9caed170a6f859a163b1 100644 (file)
@@ -53,6 +53,7 @@
                                         * network */
 #define VIRTIO_NET_F_MQ        22      /* Device supports Receive Flow
                                         * Steering */
+#define VIRTIO_NET_F_CTRL_MAC_ADDR 23  /* Set MAC address */
 
 #define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 #define VIRTIO_NET_S_ANNOUNCE  2       /* Announcement is needed */
@@ -127,7 +128,7 @@ typedef __u8 virtio_net_ctrl_ack;
  #define VIRTIO_NET_CTRL_RX_NOBCAST      5
 
 /*
- * Control the MAC filter table.
+ * Control the MAC
  *
  * The MAC filter table is managed by the hypervisor, the guest should
  * assume the size is infinite.  Filtering should be considered
@@ -140,6 +141,10 @@ typedef __u8 virtio_net_ctrl_ack;
  * first sg list contains unicast addresses, the second is for multicast.
  * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
  * is available.
+ *
+ * The ADDR_SET command requests one out scatterlist, it contains a
+ * 6 bytes MAC address. This functionality is present if the
+ * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available.
  */
 struct virtio_net_ctrl_mac {
        __u32 entries;
@@ -148,6 +153,7 @@ struct virtio_net_ctrl_mac {
 
 #define VIRTIO_NET_CTRL_MAC    1
  #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
+ #define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
 
 /*
  * Control VLAN filtering
index ed567babe789c10ef48a2db7b63e17e0a2192d65..47cb991c6ba40888377d83668eb362192e995979 100644 (file)
@@ -195,21 +195,21 @@ void local_bh_enable_ip(unsigned long ip)
 EXPORT_SYMBOL(local_bh_enable_ip);
 
 /*
- * We restart softirq processing MAX_SOFTIRQ_RESTART times,
- * and we fall back to softirqd after that.
+ * We restart softirq processing for at most 2 ms,
+ * and if need_resched() is not set.
  *
- * This number has been established via experimentation.
+ * These limits have been established via experimentation.
  * The two things to balance is latency against fairness -
  * we want to handle softirqs as soon as possible, but they
  * should not be able to lock up the box.
  */
-#define MAX_SOFTIRQ_RESTART 10
+#define MAX_SOFTIRQ_TIME  msecs_to_jiffies(2)
 
 asmlinkage void __do_softirq(void)
 {
        struct softirq_action *h;
        __u32 pending;
-       int max_restart = MAX_SOFTIRQ_RESTART;
+       unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
        int cpu;
        unsigned long old_flags = current->flags;
 
@@ -264,11 +264,12 @@ restart:
        local_irq_disable();
 
        pending = local_softirq_pending();
-       if (pending && --max_restart)
-               goto restart;
+       if (pending) {
+               if (time_before(jiffies, end) && !need_resched())
+                       goto restart;
 
-       if (pending)
                wakeup_softirqd();
+       }
 
        lockdep_softirq_exit();
 
index a292e8050ef234029611090004f1b46f889610d3..babfde9f734c899a9a58e5283d0741c8dcf4a129 100644 (file)
@@ -105,6 +105,8 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
         */
        unregister_netdevice_queue(dev, head);
 
+       netdev_upper_dev_unlink(real_dev, dev);
+
        if (grp->nr_vlan_devs == 0)
                vlan_gvrp_uninit_applicant(real_dev);
 
@@ -162,9 +164,13 @@ int register_vlan_dev(struct net_device *dev)
        if (err < 0)
                goto out_uninit_applicant;
 
+       err = netdev_upper_dev_link(real_dev, dev);
+       if (err)
+               goto out_uninit_applicant;
+
        err = register_netdevice(dev);
        if (err < 0)
-               goto out_uninit_applicant;
+               goto out_upper_dev_unlink;
 
        /* Account for reference in struct vlan_dev_priv */
        dev_hold(real_dev);
@@ -180,6 +186,8 @@ int register_vlan_dev(struct net_device *dev)
 
        return 0;
 
+out_upper_dev_unlink:
+       netdev_upper_dev_unlink(real_dev, dev);
 out_uninit_applicant:
        if (grp->nr_vlan_devs == 0)
                vlan_gvrp_uninit_applicant(real_dev);
index 65e06abe023f7fba92f468120937d84fd5911d43..380440b8ea8961932be9f3419fd4b8e8343eee09 100644 (file)
@@ -60,21 +60,25 @@ bool vlan_do_receive(struct sk_buff **skbp)
        return true;
 }
 
-/* Must be invoked with rcu_read_lock or with RTNL. */
-struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
+/* Must be invoked with rcu_read_lock. */
+struct net_device *__vlan_find_dev_deep(struct net_device *dev,
                                        u16 vlan_id)
 {
-       struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info);
+       struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info);
 
        if (vlan_info) {
                return vlan_group_get_device(&vlan_info->grp, vlan_id);
        } else {
                /*
-                * Bonding slaves do not have grp assigned to themselves.
-                * Grp is assigned to bonding master instead.
+                * Lower devices of master uppers (bonding, team) do not have
+                * grp assigned to themselves. Grp is assigned to upper device
+                * instead.
                 */
-               if (netif_is_bond_slave(real_dev))
-                       return __vlan_find_dev_deep(real_dev->master, vlan_id);
+               struct net_device *upper_dev;
+
+               upper_dev = netdev_master_upper_dev_get_rcu(dev);
+               if (upper_dev)
+                       return __vlan_find_dev_deep(upper_dev, vlan_id);
        }
 
        return NULL;
index 4a6d31a082b9e534eadc3fa2873313fa07cc7869..09f9108d4688b11ace1137530c047319b62bee49 100644 (file)
@@ -640,9 +640,9 @@ static int vlan_ethtool_get_settings(struct net_device *dev,
 static void vlan_ethtool_get_drvinfo(struct net_device *dev,
                                     struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, vlan_fullname);
-       strcpy(info->version, vlan_version);
-       strcpy(info->fw_version, "N/A");
+       strlcpy(info->driver, vlan_fullname, sizeof(info->driver));
+       strlcpy(info->version, vlan_version, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 }
 
 static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
index 30b48f523135be8f00025f32b887b51f0f7000c3..3cc5be0fe420458f7a435126b1bb135a99437f5f 100644 (file)
@@ -232,7 +232,7 @@ config RFS_ACCEL
 
 config XPS
        boolean
-       depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
+       depends on SMP && USE_GENERIC_SMP_HELPERS
        default y
 
 config NETPRIO_CGROUP
index a0ba3bff9b3648b15c8ca0aeb446573817f6dc7c..a4808c29ea3d3cdb95021c2c7130735cf21c3955 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 7d02ebd11a7f1bd13b173cbe1eb0f54e623e0345..72fe1bbf7721621391dd97f3416029960d3d4df9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -123,7 +123,7 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv)
        unsigned int msecs;
 
        msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
-       msecs += random32() % (2 * BATADV_JITTER);
+       msecs += prandom_u32() % (2 * BATADV_JITTER);
 
        return jiffies + msecs_to_jiffies(msecs);
 }
@@ -131,7 +131,7 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv)
 /* when do we schedule a ogm packet to be sent */
 static unsigned long batadv_iv_ogm_fwd_send_time(void)
 {
-       return jiffies + msecs_to_jiffies(random32() % (BATADV_JITTER / 2));
+       return jiffies + msecs_to_jiffies(prandom_u32() % (BATADV_JITTER / 2));
 }
 
 /* apply hop penalty for a normal link */
@@ -183,7 +183,6 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
        /* adjust all flags and log packets */
        while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
                                         batadv_ogm_packet->tt_num_changes)) {
-
                /* we might have aggregated direct link packets with an
                 * ordinary base packet
                 */
@@ -261,7 +260,6 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
         */
        if ((directlink && (batadv_ogm_packet->header.ttl == 1)) ||
            (forw_packet->own && (forw_packet->if_incoming != primary_if))) {
-
                /* FIXME: what about aggregated packets ? */
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
@@ -325,7 +323,6 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
        if (time_before(send_time, forw_packet->send_time) &&
            time_after_eq(aggregation_end_time, forw_packet->send_time) &&
            (aggregated_bytes <= BATADV_MAX_AGGREGATION_BYTES)) {
-
                /* check aggregation compatibility
                 * -> direct link packets are broadcasted on
                 *    their interface only
@@ -815,7 +812,6 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
        rcu_read_lock();
        hlist_for_each_entry_rcu(tmp_neigh_node, node,
                                 &orig_neigh_node->neigh_list, list) {
-
                if (!batadv_compare_eth(tmp_neigh_node->addr,
                                        orig_neigh_node->orig))
                        continue;
@@ -949,7 +945,6 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
        rcu_read_lock();
        hlist_for_each_entry_rcu(tmp_neigh_node, node,
                                 &orig_node->neigh_list, list) {
-
                is_duplicate |= batadv_test_bit(tmp_neigh_node->real_bits,
                                                orig_node->last_real_seqno,
                                                seqno);
@@ -1033,7 +1028,7 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
                is_single_hop_neigh = true;
 
        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                  "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
+                  "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %#.4x, changes %u, tq %d, TTL %d, V %d, IDF %d)\n",
                   ethhdr->h_source, if_incoming->net_dev->name,
                   if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig,
                   batadv_ogm_packet->prev_sender,
@@ -1223,7 +1218,6 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
 
        /* is single hop (direct) neighbor */
        if (is_single_hop_neigh) {
-
                /* mark direct link on incoming interface */
                batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
                                      is_single_hop_neigh,
index 5453b17d8df20249c6647bcc5c2485edfec4c1e5..973982414d58559c3ac009f2fb9b2db60a4221ea 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
index cebaae7e148b7f8a88f8b265bb625256363cde5a..a81b9322e382b42635d8689085f20d02e602c296 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
index 5aebe9327d68c8fd691243f78880c12d69951611..30f46526cbbdabee8c9b93cda29c8d7a07c36bbf 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
 static const uint8_t batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
 
 static void batadv_bla_periodic_work(struct work_struct *work);
-static void batadv_bla_send_announce(struct batadv_priv *bat_priv,
-                                    struct batadv_backbone_gw *backbone_gw);
+static void
+batadv_bla_send_announce(struct batadv_priv *bat_priv,
+                        struct batadv_bla_backbone_gw *backbone_gw);
 
 /* return the index of the claim */
 static inline uint32_t batadv_choose_claim(const void *data, uint32_t size)
 {
-       struct batadv_claim *claim = (struct batadv_claim *)data;
+       struct batadv_bla_claim *claim = (struct batadv_bla_claim *)data;
        uint32_t hash = 0;
 
        hash = batadv_hash_bytes(hash, &claim->addr, sizeof(claim->addr));
@@ -57,7 +58,7 @@ static inline uint32_t batadv_choose_claim(const void *data, uint32_t size)
 static inline uint32_t batadv_choose_backbone_gw(const void *data,
                                                 uint32_t size)
 {
-       struct batadv_claim *claim = (struct batadv_claim *)data;
+       const struct batadv_bla_claim *claim = (struct batadv_bla_claim *)data;
        uint32_t hash = 0;
 
        hash = batadv_hash_bytes(hash, &claim->addr, sizeof(claim->addr));
@@ -75,9 +76,9 @@ static inline uint32_t batadv_choose_backbone_gw(const void *data,
 static int batadv_compare_backbone_gw(const struct hlist_node *node,
                                      const void *data2)
 {
-       const void *data1 = container_of(node, struct batadv_backbone_gw,
+       const void *data1 = container_of(node, struct batadv_bla_backbone_gw,
                                         hash_entry);
-       const struct batadv_backbone_gw *gw1 = data1, *gw2 = data2;
+       const struct batadv_bla_backbone_gw *gw1 = data1, *gw2 = data2;
 
        if (!batadv_compare_eth(gw1->orig, gw2->orig))
                return 0;
@@ -92,9 +93,9 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node,
 static int batadv_compare_claim(const struct hlist_node *node,
                                const void *data2)
 {
-       const void *data1 = container_of(node, struct batadv_claim,
+       const void *data1 = container_of(node, struct batadv_bla_claim,
                                         hash_entry);
-       const struct batadv_claim *cl1 = data1, *cl2 = data2;
+       const struct batadv_bla_claim *cl1 = data1, *cl2 = data2;
 
        if (!batadv_compare_eth(cl1->addr, cl2->addr))
                return 0;
@@ -106,7 +107,8 @@ static int batadv_compare_claim(const struct hlist_node *node,
 }
 
 /* free a backbone gw */
-static void batadv_backbone_gw_free_ref(struct batadv_backbone_gw *backbone_gw)
+static void
+batadv_backbone_gw_free_ref(struct batadv_bla_backbone_gw *backbone_gw)
 {
        if (atomic_dec_and_test(&backbone_gw->refcount))
                kfree_rcu(backbone_gw, rcu);
@@ -115,16 +117,16 @@ static void batadv_backbone_gw_free_ref(struct batadv_backbone_gw *backbone_gw)
 /* finally deinitialize the claim */
 static void batadv_claim_free_rcu(struct rcu_head *rcu)
 {
-       struct batadv_claim *claim;
+       struct batadv_bla_claim *claim;
 
-       claim = container_of(rcu, struct batadv_claim, rcu);
+       claim = container_of(rcu, struct batadv_bla_claim, rcu);
 
        batadv_backbone_gw_free_ref(claim->backbone_gw);
        kfree(claim);
 }
 
 /* free a claim, call claim_free_rcu if its the last reference */
-static void batadv_claim_free_ref(struct batadv_claim *claim)
+static void batadv_claim_free_ref(struct batadv_bla_claim *claim)
 {
        if (atomic_dec_and_test(&claim->refcount))
                call_rcu(&claim->rcu, batadv_claim_free_rcu);
@@ -136,14 +138,15 @@ static void batadv_claim_free_ref(struct batadv_claim *claim)
  * looks for a claim in the hash, and returns it if found
  * or NULL otherwise.
  */
-static struct batadv_claim *batadv_claim_hash_find(struct batadv_priv *bat_priv,
-                                                  struct batadv_claim *data)
+static struct batadv_bla_claim
+*batadv_claim_hash_find(struct batadv_priv *bat_priv,
+                       struct batadv_bla_claim *data)
 {
        struct batadv_hashtable *hash = bat_priv->bla.claim_hash;
        struct hlist_head *head;
        struct hlist_node *node;
-       struct batadv_claim *claim;
-       struct batadv_claim *claim_tmp = NULL;
+       struct batadv_bla_claim *claim;
+       struct batadv_bla_claim *claim_tmp = NULL;
        int index;
 
        if (!hash)
@@ -176,15 +179,15 @@ static struct batadv_claim *batadv_claim_hash_find(struct batadv_priv *bat_priv,
  *
  * Returns claim if found or NULL otherwise.
  */
-static struct batadv_backbone_gw *
+static struct batadv_bla_backbone_gw *
 batadv_backbone_hash_find(struct batadv_priv *bat_priv,
                          uint8_t *addr, short vid)
 {
        struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
        struct hlist_head *head;
        struct hlist_node *node;
-       struct batadv_backbone_gw search_entry, *backbone_gw;
-       struct batadv_backbone_gw *backbone_gw_tmp = NULL;
+       struct batadv_bla_backbone_gw search_entry, *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw_tmp = NULL;
        int index;
 
        if (!hash)
@@ -215,12 +218,12 @@ batadv_backbone_hash_find(struct batadv_priv *bat_priv,
 
 /* delete all claims for a backbone */
 static void
-batadv_bla_del_backbone_claims(struct batadv_backbone_gw *backbone_gw)
+batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)
 {
        struct batadv_hashtable *hash;
        struct hlist_node *node, *node_tmp;
        struct hlist_head *head;
-       struct batadv_claim *claim;
+       struct batadv_bla_claim *claim;
        int i;
        spinlock_t *list_lock;  /* protects write access to the hash lists */
 
@@ -235,7 +238,6 @@ batadv_bla_del_backbone_claims(struct batadv_backbone_gw *backbone_gw)
                spin_lock_bh(list_lock);
                hlist_for_each_entry_safe(claim, node, node_tmp,
                                          head, hash_entry) {
-
                        if (claim->backbone_gw != backbone_gw)
                                continue;
 
@@ -338,7 +340,6 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac,
                           "bla_send_claim(): REQUEST of %pM to %pMon vid %d\n",
                           ethhdr->h_source, ethhdr->h_dest, vid);
                break;
-
        }
 
        if (vid != -1)
@@ -366,11 +367,11 @@ out:
  * searches for the backbone gw or creates a new one if it could not
  * be found.
  */
-static struct batadv_backbone_gw *
+static struct batadv_bla_backbone_gw *
 batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig,
                           short vid, bool own_backbone)
 {
-       struct batadv_backbone_gw *entry;
+       struct batadv_bla_backbone_gw *entry;
        struct batadv_orig_node *orig_node;
        int hash_added;
 
@@ -437,7 +438,7 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,
                                  struct batadv_hard_iface *primary_if,
                                  short vid)
 {
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
 
        backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
                                                 primary_if->net_dev->dev_addr,
@@ -462,8 +463,8 @@ static void batadv_bla_answer_request(struct batadv_priv *bat_priv,
        struct hlist_node *node;
        struct hlist_head *head;
        struct batadv_hashtable *hash;
-       struct batadv_claim *claim;
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_claim *claim;
+       struct batadv_bla_backbone_gw *backbone_gw;
        int i;
 
        batadv_dbg(BATADV_DBG_BLA, bat_priv,
@@ -502,7 +503,7 @@ static void batadv_bla_answer_request(struct batadv_priv *bat_priv,
  * After the request, it will repeat all of his own claims and finally
  * send an announcement claim with which we can check again.
  */
-static void batadv_bla_send_request(struct batadv_backbone_gw *backbone_gw)
+static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)
 {
        /* first, remove all old entries */
        batadv_bla_del_backbone_claims(backbone_gw);
@@ -528,7 +529,7 @@ static void batadv_bla_send_request(struct batadv_backbone_gw *backbone_gw)
  * places.
  */
 static void batadv_bla_send_announce(struct batadv_priv *bat_priv,
-                                    struct batadv_backbone_gw *backbone_gw)
+                                    struct batadv_bla_backbone_gw *backbone_gw)
 {
        uint8_t mac[ETH_ALEN];
        __be16 crc;
@@ -539,7 +540,6 @@ static void batadv_bla_send_announce(struct batadv_priv *bat_priv,
 
        batadv_bla_send_claim(bat_priv, mac, backbone_gw->vid,
                              BATADV_CLAIM_TYPE_ANNOUNCE);
-
 }
 
 /**
@@ -551,10 +551,10 @@ static void batadv_bla_send_announce(struct batadv_priv *bat_priv,
  */
 static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
                                 const uint8_t *mac, const short vid,
-                                struct batadv_backbone_gw *backbone_gw)
+                                struct batadv_bla_backbone_gw *backbone_gw)
 {
-       struct batadv_claim *claim;
-       struct batadv_claim search_claim;
+       struct batadv_bla_claim *claim;
+       struct batadv_bla_claim search_claim;
        int hash_added;
 
        memcpy(search_claim.addr, mac, ETH_ALEN);
@@ -598,7 +598,6 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
 
                claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
                batadv_backbone_gw_free_ref(claim->backbone_gw);
-
        }
        /* set (new) backbone gw */
        atomic_inc(&backbone_gw->refcount);
@@ -617,7 +616,7 @@ claim_free_ref:
 static void batadv_bla_del_claim(struct batadv_priv *bat_priv,
                                 const uint8_t *mac, const short vid)
 {
-       struct batadv_claim search_claim, *claim;
+       struct batadv_bla_claim search_claim, *claim;
 
        memcpy(search_claim.addr, mac, ETH_ALEN);
        search_claim.vid = vid;
@@ -643,7 +642,7 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv,
                                  uint8_t *an_addr, uint8_t *backbone_addr,
                                  short vid)
 {
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
        uint16_t crc;
 
        if (memcmp(an_addr, batadv_announce_mac, 4) != 0)
@@ -661,12 +660,12 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv,
        crc = ntohs(*((__be16 *)(&an_addr[4])));
 
        batadv_dbg(BATADV_DBG_BLA, bat_priv,
-                  "handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %04x\n",
+                  "handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %#.4x\n",
                   vid, backbone_gw->orig, crc);
 
        if (backbone_gw->crc != crc) {
                batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
-                          "handle_announce(): CRC FAILED for %pM/%d (my = %04x, sent = %04x)\n",
+                          "handle_announce(): CRC FAILED for %pM/%d (my = %#.4x, sent = %#.4x)\n",
                           backbone_gw->orig, backbone_gw->vid,
                           backbone_gw->crc, crc);
 
@@ -715,7 +714,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv,
                                 uint8_t *backbone_addr,
                                 uint8_t *claim_addr, short vid)
 {
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
 
        /* unclaim in any case if it is our own */
        if (primary_if && batadv_compare_eth(backbone_addr,
@@ -744,7 +743,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv,
                               uint8_t *backbone_addr, uint8_t *claim_addr,
                               short vid)
 {
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
 
        /* register the gateway if not yet available, and add the claim. */
 
@@ -835,7 +834,7 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv,
        /* if our mesh friends mac is bigger, use it for ourselves. */
        if (ntohs(bla_dst->group) > ntohs(bla_dst_own->group)) {
                batadv_dbg(BATADV_DBG_BLA, bat_priv,
-                          "taking other backbones claim group: %04x\n",
+                          "taking other backbones claim group: %#.4x\n",
                           ntohs(bla_dst->group));
                bla_dst_own->group = bla_dst->group;
        }
@@ -958,7 +957,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
  */
 static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)
 {
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
        struct hlist_node *node, *node_tmp;
        struct hlist_head *head;
        struct batadv_hashtable *hash;
@@ -1013,7 +1012,7 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
                                    struct batadv_hard_iface *primary_if,
                                    int now)
 {
-       struct batadv_claim *claim;
+       struct batadv_bla_claim *claim;
        struct hlist_node *node;
        struct hlist_head *head;
        struct batadv_hashtable *hash;
@@ -1062,7 +1061,7 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
                                    struct batadv_hard_iface *primary_if,
                                    struct batadv_hard_iface *oldif)
 {
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
        struct hlist_node *node;
        struct hlist_head *head;
        struct batadv_hashtable *hash;
@@ -1104,16 +1103,6 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
        }
 }
 
-
-
-/* (re)start the timer */
-static void batadv_bla_start_timer(struct batadv_priv *bat_priv)
-{
-       INIT_DELAYED_WORK(&bat_priv->bla.work, batadv_bla_periodic_work);
-       queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
-                          msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
-}
-
 /* periodic work to do:
  *  * purge structures when they are too old
  *  * send announcements
@@ -1125,7 +1114,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
        struct batadv_priv_bla *priv_bla;
        struct hlist_node *node;
        struct hlist_head *head;
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
        struct batadv_hashtable *hash;
        struct batadv_hard_iface *primary_if;
        int i;
@@ -1184,7 +1173,8 @@ out:
        if (primary_if)
                batadv_hardif_free_ref(primary_if);
 
-       batadv_bla_start_timer(bat_priv);
+       queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
+                          msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
 }
 
 /* The hash for claim and backbone hash receive the same key because they
@@ -1242,7 +1232,10 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
 
        batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hashes initialized\n");
 
-       batadv_bla_start_timer(bat_priv);
+       INIT_DELAYED_WORK(&bat_priv->bla.work, batadv_bla_periodic_work);
+
+       queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
+                          msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
        return 0;
 }
 
@@ -1330,7 +1323,7 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig)
        struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
        struct hlist_head *head;
        struct hlist_node *node;
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
        int i;
 
        if (!atomic_read(&bat_priv->bridge_loop_avoidance))
@@ -1371,7 +1364,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
 {
        struct ethhdr *ethhdr;
        struct vlan_ethhdr *vhdr;
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
        short vid = -1;
 
        if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
@@ -1442,7 +1435,7 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid,
                  bool is_bcast)
 {
        struct ethhdr *ethhdr;
-       struct batadv_claim search_claim, *claim = NULL;
+       struct batadv_bla_claim search_claim, *claim = NULL;
        struct batadv_hard_iface *primary_if;
        int ret;
 
@@ -1536,7 +1529,7 @@ out:
 int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, short vid)
 {
        struct ethhdr *ethhdr;
-       struct batadv_claim search_claim, *claim = NULL;
+       struct batadv_bla_claim search_claim, *claim = NULL;
        struct batadv_hard_iface *primary_if;
        int ret = 0;
 
@@ -1612,7 +1605,7 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
        struct net_device *net_dev = (struct net_device *)seq->private;
        struct batadv_priv *bat_priv = netdev_priv(net_dev);
        struct batadv_hashtable *hash = bat_priv->bla.claim_hash;
-       struct batadv_claim *claim;
+       struct batadv_bla_claim *claim;
        struct batadv_hard_iface *primary_if;
        struct hlist_node *node;
        struct hlist_head *head;
@@ -1626,10 +1619,10 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
 
        primary_addr = primary_if->net_dev->dev_addr;
        seq_printf(seq,
-                  "Claims announced for the mesh %s (orig %pM, group id %04x)\n",
+                  "Claims announced for the mesh %s (orig %pM, group id %#.4x)\n",
                   net_dev->name, primary_addr,
                   ntohs(bat_priv->bla.claim_dest.group));
-       seq_printf(seq, "   %-17s    %-5s    %-17s [o] (%-4s)\n",
+       seq_printf(seq, "   %-17s    %-5s    %-17s [o] (%-6s)\n",
                   "Client", "VID", "Originator", "CRC");
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -1638,7 +1631,7 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
                hlist_for_each_entry_rcu(claim, node, head, hash_entry) {
                        is_own = batadv_compare_eth(claim->backbone_gw->orig,
                                                    primary_addr);
-                       seq_printf(seq, " * %pM on % 5d by %pM [%c] (%04x)\n",
+                       seq_printf(seq, " * %pM on % 5d by %pM [%c] (%#.4x)\n",
                                   claim->addr, claim->vid,
                                   claim->backbone_gw->orig,
                                   (is_own ? 'x' : ' '),
@@ -1657,7 +1650,7 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
        struct net_device *net_dev = (struct net_device *)seq->private;
        struct batadv_priv *bat_priv = netdev_priv(net_dev);
        struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
-       struct batadv_backbone_gw *backbone_gw;
+       struct batadv_bla_backbone_gw *backbone_gw;
        struct batadv_hard_iface *primary_if;
        struct hlist_node *node;
        struct hlist_head *head;
@@ -1672,10 +1665,10 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
 
        primary_addr = primary_if->net_dev->dev_addr;
        seq_printf(seq,
-                  "Backbones announced for the mesh %s (orig %pM, group id %04x)\n",
+                  "Backbones announced for the mesh %s (orig %pM, group id %#.4x)\n",
                   net_dev->name, primary_addr,
                   ntohs(bat_priv->bla.claim_dest.group));
-       seq_printf(seq, "   %-17s    %-5s %-9s (%-4s)\n",
+       seq_printf(seq, "   %-17s    %-5s %-9s (%-6s)\n",
                   "Originator", "VID", "last seen", "CRC");
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -1693,7 +1686,7 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
                                continue;
 
                        seq_printf(seq,
-                                  " * %pM on % 5d % 4i.%03is (%04x)\n",
+                                  " * %pM on % 5d % 4i.%03is (%#.4x)\n",
                                   backbone_gw->orig, backbone_gw->vid,
                                   secs, msecs, backbone_gw->crc);
                }
index 196d9a0254bcbc6820c5f60f3c53a63638b683c9..dea2fbc5d98d00d020608db19e51e830501c93a7 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
index 6f58ddd53bff8d2752c7a59dda1c20e40ec428e0..6ae86516db4dcebd6125d8d04976c33a06ff9f5f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -40,13 +40,14 @@ static struct dentry *batadv_debugfs;
 
 static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
 
-static char *batadv_log_char_addr(struct batadv_debug_log *debug_log,
+static char *batadv_log_char_addr(struct batadv_priv_debug_log *debug_log,
                                  size_t idx)
 {
        return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK];
 }
 
-static void batadv_emit_log_char(struct batadv_debug_log *debug_log, char c)
+static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log,
+                                char c)
 {
        char *char_addr;
 
@@ -59,7 +60,7 @@ static void batadv_emit_log_char(struct batadv_debug_log *debug_log, char c)
 }
 
 __printf(2, 3)
-static int batadv_fdebug_log(struct batadv_debug_log *debug_log,
+static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log,
                             const char *fmt, ...)
 {
        va_list args;
@@ -114,7 +115,7 @@ static int batadv_log_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int batadv_log_empty(struct batadv_debug_log *debug_log)
+static int batadv_log_empty(struct batadv_priv_debug_log *debug_log)
 {
        return !(debug_log->log_start - debug_log->log_end);
 }
@@ -123,7 +124,7 @@ static ssize_t batadv_log_read(struct file *file, char __user *buf,
                               size_t count, loff_t *ppos)
 {
        struct batadv_priv *bat_priv = file->private_data;
-       struct batadv_debug_log *debug_log = bat_priv->debug_log;
+       struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
        int error, i = 0;
        char *char_addr;
        char c;
@@ -164,7 +165,6 @@ static ssize_t batadv_log_read(struct file *file, char __user *buf,
 
                buf++;
                i++;
-
        }
 
        spin_unlock_bh(&debug_log->lock);
@@ -178,7 +178,7 @@ static ssize_t batadv_log_read(struct file *file, char __user *buf,
 static unsigned int batadv_log_poll(struct file *file, poll_table *wait)
 {
        struct batadv_priv *bat_priv = file->private_data;
-       struct batadv_debug_log *debug_log = bat_priv->debug_log;
+       struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
 
        poll_wait(file, &debug_log->queue_wait, wait);
 
@@ -230,7 +230,6 @@ static void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
 #else /* CONFIG_BATMAN_ADV_DEBUG */
 static int batadv_debug_log_setup(struct batadv_priv *bat_priv)
 {
-       bat_priv->debug_log = NULL;
        return 0;
 }
 
@@ -397,10 +396,8 @@ err:
 
 void batadv_debugfs_destroy(void)
 {
-       if (batadv_debugfs) {
-               debugfs_remove_recursive(batadv_debugfs);
-               batadv_debugfs = NULL;
-       }
+       debugfs_remove_recursive(batadv_debugfs);
+       batadv_debugfs = NULL;
 }
 
 int batadv_debugfs_add_meshif(struct net_device *dev)
index 3319e1f21f555f8d044d96a79cb14adf83772a46..f8c3849edff428e3d98fbd7f74edfece03235400 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 183f97a86bb24c8099f4d3b7b7d4a5919d3432c4..ea0bd31d41c2671e25d2f5f539d5aa823f743b9a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
  *
  * Antonio Quartulli
  *
index d060c033e7de097dc4d5272f4595161082ca135a..125c8c6fcfadfed4d8b388d3f7775877a5b6ff93 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
  *
  * Antonio Quartulli
  *
index dd07c7e3654fa4b3e38f9c0665ca705a332203cc..074107f2cfaa554b02ece1b327cf7bd105d83bc6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index f0d129e323c88b2f0747fabec25d9d8f8d8fe495..039902dca4a691074856d7846c59ad89f0bd8b8e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 9001208d1752cbd5f32fd5dadcbe49d7ffc2920b..84bb2b18d7110a4597dc71c7b2f68c032d7750a9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 13697f6e71131e3f2cff82febf3c43486909e81d..509b2bf8c2f4fa6388e095c998dd0006ec3d9b6e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index f1d37cd818155ed82b388571a2342afb39509897..368219e026a96fbf2ca50df30cb49bd2c54d5978 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -457,6 +457,24 @@ out:
                batadv_hardif_free_ref(primary_if);
 }
 
+/**
+ * batadv_hardif_remove_interface_finish - cleans up the remains of a hardif
+ * @work: work queue item
+ *
+ * Free the parts of the hard interface which can not be removed under
+ * rtnl lock (to prevent deadlock situations).
+ */
+static void batadv_hardif_remove_interface_finish(struct work_struct *work)
+{
+       struct batadv_hard_iface *hard_iface;
+
+       hard_iface = container_of(work, struct batadv_hard_iface,
+                                 cleanup_work);
+
+       batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
+       batadv_hardif_free_ref(hard_iface);
+}
+
 static struct batadv_hard_iface *
 batadv_hardif_add_interface(struct net_device *net_dev)
 {
@@ -484,6 +502,9 @@ batadv_hardif_add_interface(struct net_device *net_dev)
        hard_iface->soft_iface = NULL;
        hard_iface->if_status = BATADV_IF_NOT_IN_USE;
        INIT_LIST_HEAD(&hard_iface->list);
+       INIT_WORK(&hard_iface->cleanup_work,
+                 batadv_hardif_remove_interface_finish);
+
        /* extra reference for return */
        atomic_set(&hard_iface->refcount, 2);
 
@@ -518,8 +539,7 @@ static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
                return;
 
        hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
-       batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
-       batadv_hardif_free_ref(hard_iface);
+       queue_work(batadv_event_workqueue, &hard_iface->cleanup_work);
 }
 
 void batadv_hardif_remove_interfaces(void)
index 3732366e7445b478df99015454b093cdc2c26665..308437d52e221f3dfdaf917cfeee8676dd422c20 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
index 15a849c2d41498989c82ff9d86740eb5cfe4d7cb..7198dafd3bf353b97c13a798d1daeed705fb4e30 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
index e05333905afd566117bf1267d6e3ac05596c89c1..1b4da72f2093e0f77b08702febf7a0f120e12ff8 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -89,7 +89,7 @@ static inline void batadv_hash_delete(struct batadv_hashtable *hash,
  *
  *     Returns the new hash value.
  */
-static inline uint32_t batadv_hash_bytes(uint32_t hash, void *data,
+static inline uint32_t batadv_hash_bytes(uint32_t hash, const void *data,
                                         uint32_t size)
 {
        const unsigned char *key = data;
index 87ca8095b011517b6f41faf8d1dfa25ef8e0b570..0ba6c899b2d3512b9dd0bc0c4292fcf08d1f0154 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 29443a1dbb5c80f0147179d387244386c49e4370..1fcca37b62234d92b2e6092dcdc4ccfed4d76ba2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index f65a222b7b83c0d691f859f2eef1ea189ac84e2c..21fe6987733bf0d635fca38f22c826ca4bdb9b4b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
index 2f85577086a7cf923c6185f84f6efeb3bfb5fe84..ced08b936a9690a6f7d01af7f7eb8a31f3e1f29d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -26,7 +26,7 @@
 #define BATADV_DRIVER_DEVICE "batman-adv"
 
 #ifndef BATADV_SOURCE_VERSION
-#define BATADV_SOURCE_VERSION "2012.5.0"
+#define BATADV_SOURCE_VERSION "2013.1.0"
 #endif
 
 /* B.A.T.M.A.N. parameters */
  * -> TODO: check influence on BATADV_TQ_LOCAL_WINDOW_SIZE
  */
 #define BATADV_PURGE_TIMEOUT 200000 /* 200 seconds */
-#define BATADV_TT_LOCAL_TIMEOUT 3600000 /* in milliseconds */
+#define BATADV_TT_LOCAL_TIMEOUT 600000 /* in milliseconds */
 #define BATADV_TT_CLIENT_ROAM_TIMEOUT 600000 /* in milliseconds */
 #define BATADV_TT_CLIENT_TEMP_TIMEOUT 600000 /* in milliseconds */
+#define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */
+#define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
 #define BATADV_DAT_ENTRY_TIMEOUT (5*60000) /* 5 mins in milliseconds */
 /* sliding packet range of received originator messages in sequence numbers
  * (should be a multiple of our word size)
@@ -276,9 +278,7 @@ static inline bool batadv_has_timed_out(unsigned long timestamp,
 static inline void batadv_add_counter(struct batadv_priv *bat_priv, size_t idx,
                                      size_t count)
 {
-       int cpu = get_cpu();
-       per_cpu_ptr(bat_priv->bat_counters, cpu)[idx] += count;
-       put_cpu();
+       this_cpu_add(bat_priv->bat_counters[idx], count);
 }
 
 #define batadv_inc_counter(b, i) batadv_add_counter(b, i, 1)
index 8c32cf1c2deca7177945a804afcdf6ad10572ee5..457ea445217c2dd7eec34647b9e8969d93590707 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
 #include "soft-interface.h"
 #include "bridge_loop_avoidance.h"
 
-static void batadv_purge_orig(struct work_struct *work);
+/* hash class keys */
+static struct lock_class_key batadv_orig_hash_lock_class_key;
 
-static void batadv_start_purge_timer(struct batadv_priv *bat_priv)
-{
-       INIT_DELAYED_WORK(&bat_priv->orig_work, batadv_purge_orig);
-       queue_delayed_work(batadv_event_workqueue,
-                          &bat_priv->orig_work, msecs_to_jiffies(1000));
-}
+static void batadv_purge_orig(struct work_struct *work);
 
 /* returns 1 if they are the same originator */
 static int batadv_compare_orig(const struct hlist_node *node, const void *data2)
@@ -57,7 +53,14 @@ int batadv_originator_init(struct batadv_priv *bat_priv)
        if (!bat_priv->orig_hash)
                goto err;
 
-       batadv_start_purge_timer(bat_priv);
+       batadv_hash_set_lock_class(bat_priv->orig_hash,
+                                  &batadv_orig_hash_lock_class_key);
+
+       INIT_DELAYED_WORK(&bat_priv->orig_work, batadv_purge_orig);
+       queue_delayed_work(batadv_event_workqueue,
+                          &bat_priv->orig_work,
+                          msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
+
        return 0;
 
 err:
@@ -178,7 +181,6 @@ void batadv_originator_free(struct batadv_priv *bat_priv)
                spin_lock_bh(list_lock);
                hlist_for_each_entry_safe(orig_node, node, node_tmp,
                                          head, hash_entry) {
-
                        hlist_del_rcu(node);
                        batadv_orig_node_free_ref(orig_node);
                }
@@ -285,7 +287,6 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
        /* for all neighbors towards this originator ... */
        hlist_for_each_entry_safe(neigh_node, node, node_tmp,
                                  &orig_node->neigh_list, list) {
-
                last_seen = neigh_node->last_seen;
                if_incoming = neigh_node->if_incoming;
 
@@ -293,7 +294,6 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
                    (if_incoming->if_status == BATADV_IF_INACTIVE) ||
                    (if_incoming->if_status == BATADV_IF_NOT_IN_USE) ||
                    (if_incoming->if_status == BATADV_IF_TO_BE_REMOVED)) {
-
                        if ((if_incoming->if_status == BATADV_IF_INACTIVE) ||
                            (if_incoming->if_status == BATADV_IF_NOT_IN_USE) ||
                            (if_incoming->if_status == BATADV_IF_TO_BE_REMOVED))
@@ -393,7 +393,9 @@ static void batadv_purge_orig(struct work_struct *work)
        delayed_work = container_of(work, struct delayed_work, work);
        bat_priv = container_of(delayed_work, struct batadv_priv, orig_work);
        _batadv_purge_orig(bat_priv);
-       batadv_start_purge_timer(bat_priv);
+       queue_delayed_work(batadv_event_workqueue,
+                          &bat_priv->orig_work,
+                          msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
 }
 
 void batadv_purge_orig_ref(struct batadv_priv *bat_priv)
index 9778e656dec73bb5c1cb44e126cbe03d80052359..286bf743e76a34e0519d9ba6c9c871c3b3295105 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
index cb6405bf755cdbdf24b005b38416999e9ec38e19..ed0aa89bbf8b7bae0fdf70c5421598c1a04df2d2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
index c8f61e395b74864de3ef5c7944074358eda1706c..ccab0bbdbb599d1f6e192f15d7c6708326745b7d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index fda8c17df273fb82731d3ef8ecfb25d18bac97bf..3f92ae248e83dbbd9b43f373197728828f77cd49 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 1aa1722d01870d69738f6be60a7e7868882cab88..60ba03fc83904f3008d7b7bd6b064955f0809b81 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -80,7 +80,6 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
 
        /* route added */
        } else if ((!curr_router) && (neigh_node)) {
-
                batadv_dbg(BATADV_DBG_ROUTES, bat_priv,
                           "Adding route towards: %pM (via %pM)\n",
                           orig_node->orig, neigh_node->addr);
@@ -172,7 +171,6 @@ void batadv_bonding_candidate_add(struct batadv_orig_node *orig_node,
         */
        hlist_for_each_entry_rcu(tmp_neigh_node, node,
                                 &orig_node->neigh_list, list) {
-
                if (tmp_neigh_node == neigh_node)
                        continue;
 
@@ -836,7 +834,6 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
        if (unicast_packet->header.packet_type == BATADV_UNICAST_FRAG &&
            batadv_frag_can_reassemble(skb,
                                       neigh_node->if_incoming->net_dev->mtu)) {
-
                ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb);
 
                if (ret == NET_RX_DROP)
@@ -1103,7 +1100,6 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
 
        /* packet for me */
        if (batadv_is_my_mac(unicast_packet->dest)) {
-
                ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb);
 
                if (ret == NET_RX_DROP)
index 9262279ea6677888f6b20d72d2658cb7171458bf..99eeafaba4075a37df1562e7e1b890b6a717fb71 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
index 4425af9dad40e2b9698f48c576c27042c13a8dbb..80ca65fc89a19e76b599f0df8c80aa4b811e520b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -155,8 +155,6 @@ _batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
        spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
 
        /* start timer for this packet */
-       INIT_DELAYED_WORK(&forw_packet->delayed_work,
-                         batadv_send_outstanding_bcast_packet);
        queue_delayed_work(batadv_event_workqueue, &forw_packet->delayed_work,
                           send_time);
 }
@@ -210,6 +208,9 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
        /* how often did we send the bcast packet ? */
        forw_packet->num_packets = 0;
 
+       INIT_DELAYED_WORK(&forw_packet->delayed_work,
+                         batadv_send_outstanding_bcast_packet);
+
        _batadv_add_bcast_packet_to_list(bat_priv, forw_packet, delay);
        return NETDEV_TX_OK;
 
@@ -330,7 +331,6 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
        spin_lock_bh(&bat_priv->forw_bcast_list_lock);
        hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
                                  &bat_priv->forw_bcast_list, list) {
-
                /* if purge_outstanding_packets() was called with an argument
                 * we delete only packets belonging to the given interface
                 */
@@ -357,7 +357,6 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
        spin_lock_bh(&bat_priv->forw_bat_list_lock);
        hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
                                  &bat_priv->forw_bat_list, list) {
-
                /* if purge_outstanding_packets() was called with an argument
                 * we delete only packets belonging to the given interface
                 */
index 0078dece1abcd4cf6784b59cf5441ac150424330..38e662f619ac6e45bebed3b982f444396ea94bd8 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
index 6b548fde8e0435fece3a67f9ea0f94a1f8aae693..2711e870f557d43ac6bbd4180a7f239a27fb850a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -124,7 +124,6 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
                batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX);
        }
 
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        return 0;
 }
 
@@ -181,7 +180,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
                goto dropped;
 
        /* Register the client MAC in the transtable */
-       batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
+       if (!is_multicast_ether_addr(ethhdr->h_source))
+               batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
 
        /* don't accept stp packets. STP does not help in meshes.
         * better use the bridge loop avoidance ...
@@ -449,6 +449,30 @@ static void batadv_interface_setup(struct net_device *dev)
        memset(priv, 0, sizeof(*priv));
 }
 
+/**
+ * batadv_softif_destroy_finish - cleans up the remains of a softif
+ * @work: work queue item
+ *
+ * Free the parts of the soft interface which can not be removed under
+ * rtnl lock (to prevent deadlock situations).
+ */
+static void batadv_softif_destroy_finish(struct work_struct *work)
+{
+       struct batadv_priv *bat_priv;
+       struct net_device *soft_iface;
+
+       bat_priv = container_of(work, struct batadv_priv,
+                               cleanup_work);
+       soft_iface = bat_priv->soft_iface;
+
+       batadv_debugfs_del_meshif(soft_iface);
+       batadv_sysfs_del_meshif(soft_iface);
+
+       rtnl_lock();
+       unregister_netdevice(soft_iface);
+       rtnl_unlock();
+}
+
 struct net_device *batadv_softif_create(const char *name)
 {
        struct net_device *soft_iface;
@@ -463,6 +487,8 @@ struct net_device *batadv_softif_create(const char *name)
                goto out;
 
        bat_priv = netdev_priv(soft_iface);
+       bat_priv->soft_iface = soft_iface;
+       INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish);
 
        /* batadv_interface_stats() needs to be available as soon as
         * register_netdevice() has been called
@@ -480,7 +506,9 @@ struct net_device *batadv_softif_create(const char *name)
 
        atomic_set(&bat_priv->aggregated_ogms, 1);
        atomic_set(&bat_priv->bonding, 0);
+#ifdef CONFIG_BATMAN_ADV_BLA
        atomic_set(&bat_priv->bridge_loop_avoidance, 0);
+#endif
 #ifdef CONFIG_BATMAN_ADV_DAT
        atomic_set(&bat_priv->distributed_arp_table, 1);
 #endif
@@ -491,7 +519,9 @@ struct net_device *batadv_softif_create(const char *name)
        atomic_set(&bat_priv->gw_bandwidth, 41);
        atomic_set(&bat_priv->orig_interval, 1000);
        atomic_set(&bat_priv->hop_penalty, 30);
+#ifdef CONFIG_BATMAN_ADV_DEBUG
        atomic_set(&bat_priv->log_level, 0);
+#endif
        atomic_set(&bat_priv->fragmentation, 1);
        atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN);
        atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN);
@@ -547,10 +577,10 @@ out:
 
 void batadv_softif_destroy(struct net_device *soft_iface)
 {
-       batadv_debugfs_del_meshif(soft_iface);
-       batadv_sysfs_del_meshif(soft_iface);
+       struct batadv_priv *bat_priv = netdev_priv(soft_iface);
+
        batadv_mesh_free(soft_iface);
-       unregister_netdevice(soft_iface);
+       queue_work(batadv_event_workqueue, &bat_priv->cleanup_work);
 }
 
 int batadv_softif_is_valid(const struct net_device *net_dev)
@@ -581,10 +611,10 @@ static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void batadv_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "B.A.T.M.A.N. advanced");
-       strcpy(info->version, BATADV_SOURCE_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, "batman");
+       strlcpy(info->driver, "B.A.T.M.A.N. advanced", sizeof(info->driver));
+       strlcpy(info->version, BATADV_SOURCE_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, "batman", sizeof(info->bus_info));
 }
 
 static u32 batadv_get_msglevel(struct net_device *dev)
index 07a08fed28b97ae2739e8a7cb36040f75345a951..43182e5e603aafd4dead1fa516472c4bc4ee5dc4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 84a55cb19b0b9b2d4e5c9f2d787bf916059556db..afbba319d73af8fb96fb80f14da86416a95a86ef 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 3fd1412b06202fe3526dcd5b10e4ac2a40458edd..479acf4c16f47d1068698d15362099459544af79 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
index 22457a7952baae3fc85c3ce43bd14bbeb5acf068..fb15b4c076f77e901cc56a59ad31d50a42caa5b5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
  *
 
 #include <linux/crc16.h>
 
+/* hash class keys */
+static struct lock_class_key batadv_tt_local_hash_lock_class_key;
+static struct lock_class_key batadv_tt_global_hash_lock_class_key;
+
 static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
                                 struct batadv_orig_node *orig_node);
 static void batadv_tt_purge(struct work_struct *work);
@@ -48,13 +52,6 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
        return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 }
 
-static void batadv_tt_start_timer(struct batadv_priv *bat_priv)
-{
-       INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
-       queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
-                          msecs_to_jiffies(5000));
-}
-
 static struct batadv_tt_common_entry *
 batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data)
 {
@@ -112,7 +109,6 @@ batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data)
                                               struct batadv_tt_global_entry,
                                               common);
        return tt_global_entry;
-
 }
 
 static void
@@ -235,6 +231,9 @@ static int batadv_tt_local_init(struct batadv_priv *bat_priv)
        if (!bat_priv->tt.local_hash)
                return -ENOMEM;
 
+       batadv_hash_set_lock_class(bat_priv->tt.local_hash,
+                                  &batadv_tt_local_hash_lock_class_key);
+
        return 0;
 }
 
@@ -249,7 +248,6 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
        batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
                           batadv_choose_orig, tt_global->common.addr);
        batadv_tt_global_entry_free_ref(tt_global);
-
 }
 
 void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
@@ -305,7 +303,11 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
                   (uint8_t)atomic_read(&bat_priv->tt.vn));
 
        memcpy(tt_local->common.addr, addr, ETH_ALEN);
-       tt_local->common.flags = BATADV_NO_FLAGS;
+       /* The local entry has to be marked as NEW to avoid to send it in
+        * a full table response going out before the next ttvn increment
+        * (consistency check)
+        */
+       tt_local->common.flags = BATADV_TT_CLIENT_NEW;
        if (batadv_is_wifi_iface(ifindex))
                tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
        atomic_set(&tt_local->common.refcount, 2);
@@ -316,12 +318,6 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
        if (batadv_compare_eth(addr, soft_iface->dev_addr))
                tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
 
-       /* The local entry has to be marked as NEW to avoid to send it in
-        * a full table response going out before the next ttvn increment
-        * (consistency check)
-        */
-       tt_local->common.flags |= BATADV_TT_CLIENT_NEW;
-
        hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
                                     batadv_choose_orig, &tt_local->common,
                                     &tt_local->common.hash_entry);
@@ -472,18 +468,27 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
        struct batadv_priv *bat_priv = netdev_priv(net_dev);
        struct batadv_hashtable *hash = bat_priv->tt.local_hash;
        struct batadv_tt_common_entry *tt_common_entry;
+       struct batadv_tt_local_entry *tt_local;
        struct batadv_hard_iface *primary_if;
        struct hlist_node *node;
        struct hlist_head *head;
        uint32_t i;
+       int last_seen_secs;
+       int last_seen_msecs;
+       unsigned long last_seen_jiffies;
+       bool no_purge;
+       uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE;
 
        primary_if = batadv_seq_print_text_primary_if_get(seq);
        if (!primary_if)
                goto out;
 
        seq_printf(seq,
-                  "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
-                  net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn));
+                  "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.4x):\n",
+                  net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn),
+                  bat_priv->tt.local_crc);
+       seq_printf(seq, "       %-13s %-7s %-10s\n", "Client", "Flags",
+                  "Last seen");
 
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -491,18 +496,29 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
                rcu_read_lock();
                hlist_for_each_entry_rcu(tt_common_entry, node,
                                         head, hash_entry) {
-                       seq_printf(seq, " * %pM [%c%c%c%c%c]\n",
+                       tt_local = container_of(tt_common_entry,
+                                               struct batadv_tt_local_entry,
+                                               common);
+                       last_seen_jiffies = jiffies - tt_local->last_seen;
+                       last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
+                       last_seen_secs = last_seen_msecs / 1000;
+                       last_seen_msecs = last_seen_msecs % 1000;
+
+                       no_purge = tt_common_entry->flags & np_flag;
+
+                       seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n",
                                   tt_common_entry->addr,
                                   (tt_common_entry->flags &
                                    BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
-                                  (tt_common_entry->flags &
-                                   BATADV_TT_CLIENT_NOPURGE ? 'P' : '.'),
+                                  no_purge ? 'P' : '.',
                                   (tt_common_entry->flags &
                                    BATADV_TT_CLIENT_NEW ? 'N' : '.'),
                                   (tt_common_entry->flags &
                                    BATADV_TT_CLIENT_PENDING ? 'X' : '.'),
                                   (tt_common_entry->flags &
-                                   BATADV_TT_CLIENT_WIFI ? 'W' : '.'));
+                                   BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
+                                  no_purge ? last_seen_secs : 0,
+                                  no_purge ? last_seen_msecs : 0);
                }
                rcu_read_unlock();
        }
@@ -627,7 +643,6 @@ static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
                batadv_tt_local_purge_list(bat_priv, head);
                spin_unlock_bh(list_lock);
        }
-
 }
 
 static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
@@ -676,6 +691,9 @@ static int batadv_tt_global_init(struct batadv_priv *bat_priv)
        if (!bat_priv->tt.global_hash)
                return -ENOMEM;
 
+       batadv_hash_set_lock_class(bat_priv->tt.global_hash,
+                                  &batadv_tt_global_hash_lock_class_key);
+
        return 0;
 }
 
@@ -967,10 +985,11 @@ batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry,
        best_entry = batadv_transtable_best_orig(tt_global_entry);
        if (best_entry) {
                last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
-               seq_printf(seq, " %c %pM  (%3u) via %pM     (%3u)   [%c%c%c]\n",
+               seq_printf(seq,
+                          " %c %pM  (%3u) via %pM     (%3u)   (%#.4x) [%c%c%c]\n",
                           '*', tt_global_entry->common.addr,
                           best_entry->ttvn, best_entry->orig_node->orig,
-                          last_ttvn,
+                          last_ttvn, best_entry->orig_node->tt_crc,
                           (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
                           (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
                           (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
@@ -1012,8 +1031,9 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
        seq_printf(seq,
                   "Globally announced TT entries received via the mesh %s\n",
                   net_dev->name);
-       seq_printf(seq, "       %-13s %s       %-15s %s %s\n",
-                  "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
+       seq_printf(seq, "       %-13s %s       %-15s %s (%-6s) %s\n",
+                  "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC",
+                  "Flags");
 
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -1049,7 +1069,6 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
                batadv_tt_orig_list_entry_free_ref(orig_entry);
        }
        spin_unlock_bh(&tt_global_entry->list_lock);
-
 }
 
 static void
@@ -1825,7 +1844,6 @@ out:
        if (!ret)
                kfree_skb(skb);
        return ret;
-
 }
 
 static bool
@@ -2111,7 +2129,9 @@ int batadv_tt_init(struct batadv_priv *bat_priv)
        if (ret < 0)
                return ret;
 
-       batadv_tt_start_timer(bat_priv);
+       INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge);
+       queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
+                          msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
 
        return 1;
 }
@@ -2261,7 +2281,8 @@ static void batadv_tt_purge(struct work_struct *work)
        batadv_tt_req_purge(bat_priv);
        batadv_tt_roam_purge(bat_priv);
 
-       batadv_tt_start_timer(bat_priv);
+       queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work,
+                          msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
 }
 
 void batadv_tt_free(struct batadv_priv *bat_priv)
@@ -2352,7 +2373,6 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
                }
                spin_unlock_bh(list_lock);
        }
-
 }
 
 static int batadv_tt_commit_changes(struct batadv_priv *bat_priv,
@@ -2496,7 +2516,7 @@ void batadv_tt_update_orig(struct batadv_priv *bat_priv,
                    orig_node->tt_crc != tt_crc) {
 request_table:
                        batadv_dbg(BATADV_DBG_TT, bat_priv,
-                                  "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %u last_crc: %u num_changes: %u)\n",
+                                  "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.4x last_crc: %#.4x num_changes: %u)\n",
                                   orig_node->orig, ttvn, orig_ttvn, tt_crc,
                                   orig_node->tt_crc, tt_num_changes);
                        batadv_send_tt_request(bat_priv, orig_node, ttvn,
@@ -2549,7 +2569,6 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
        batadv_tt_local_entry_free_ref(tt_local_entry);
 out:
        return ret;
-
 }
 
 bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
index 46d4451a59ee8feb6ce895473d6df838e97f8326..ab8e683b402f0686a6e1ffe4168f99961c898bc4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
  *
index ae9ac9aca8c53d5ffd93b015cb6ff779f55c86fe..4cd87a0b5b8037d12c9af6ed1d78d515b598af0f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -24,6 +24,9 @@
 #include "bitarray.h"
 #include <linux/kernel.h>
 
+/**
+ * Maximum overhead for the encapsulation for a payload packet
+ */
 #define BATADV_HEADER_LEN \
        (ETH_HLEN + max(sizeof(struct batadv_unicast_packet), \
                        sizeof(struct batadv_bcast_packet)))
@@ -51,6 +54,22 @@ struct batadv_hard_iface_bat_iv {
        atomic_t ogm_seqno;
 };
 
+/**
+ * struct batadv_hard_iface - network device known to batman-adv
+ * @list: list node for batadv_hardif_list
+ * @if_num: identificator of the interface
+ * @if_status: status of the interface for batman-adv
+ * @net_dev: pointer to the net_device
+ * @frag_seqno: last fragment sequence number sent by this interface
+ * @hardif_obj: kobject of the per interface sysfs "mesh" directory
+ * @refcount: number of contexts the object is used
+ * @batman_adv_ptype: packet type describing packets that should be processed by
+ *  batman-adv for this interface
+ * @soft_iface: the batman-adv interface which uses this network interface
+ * @rcu: struct used for freeing in an RCU-safe manner
+ * @bat_iv: BATMAN IV specific per hard interface data
+ * @cleanup_work: work queue callback item for hard interface deinit
+ */
 struct batadv_hard_iface {
        struct list_head list;
        int16_t if_num;
@@ -63,22 +82,52 @@ struct batadv_hard_iface {
        struct net_device *soft_iface;
        struct rcu_head rcu;
        struct batadv_hard_iface_bat_iv bat_iv;
+       struct work_struct cleanup_work;
 };
 
 /**
- *     struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
- *     @primary_addr: hosts primary interface address
- *     @last_seen: when last packet from this node was received
- *     @bcast_seqno_reset: time when the broadcast seqno window was reset
- *     @batman_seqno_reset: time when the batman seqno window was reset
- *     @gw_flags: flags related to gateway class
- *     @flags: for now only VIS_SERVER flag
- *     @last_real_seqno: last and best known sequence number
- *     @last_ttl: ttl of last received packet
- *     @last_bcast_seqno: last broadcast sequence number received by this host
- *
- *     @candidates: how many candidates are available
- *     @selected: next bonding candidate
+ * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
+ * @orig: originator ethernet address
+ * @primary_addr: hosts primary interface address
+ * @router: router that should be used to reach this originator
+ * @batadv_dat_addr_t:  address of the orig node in the distributed hash
+ * @bcast_own: bitfield containing the number of our OGMs this orig_node
+ *  rebroadcasted "back" to us (relative to last_real_seqno)
+ * @bcast_own_sum: counted result of bcast_own
+ * @last_seen: time when last packet from this node was received
+ * @bcast_seqno_reset: time when the broadcast seqno window was reset
+ * @batman_seqno_reset: time when the batman seqno window was reset
+ * @gw_flags: flags related to gateway class
+ * @flags: for now only VIS_SERVER flag
+ * @last_ttvn: last seen translation table version number
+ * @tt_crc: CRC of the translation table
+ * @tt_buff: last tt changeset this node received from the orig node
+ * @tt_buff_len: length of the last tt changeset this node received from the
+ *  orig node
+ * @tt_buff_lock: lock that protects tt_buff and tt_buff_len
+ * @tt_size: number of global TT entries announced by the orig node
+ * @tt_initialised: bool keeping track of whether or not this node have received
+ *  any translation table information from the orig node yet
+ * @last_real_seqno: last and best known sequence number
+ * @last_ttl: ttl of last received packet
+ * @bcast_bits: bitfield containing the info which payload broadcast originated
+ *  from this orig node this host already has seen (relative to
+ *  last_bcast_seqno)
+ * @last_bcast_seqno: last broadcast sequence number received by this host
+ * @neigh_list: list of potential next hop neighbor towards this orig node
+ * @frag_list: fragmentation buffer list for fragment re-assembly
+ * @last_frag_packet: time when last fragmented packet from this node was
+ *  received
+ * @neigh_list_lock: lock protecting neigh_list, router and bonding_list
+ * @hash_entry: hlist node for batadv_priv::orig_hash
+ * @bat_priv: pointer to soft_iface this orig node belongs to
+ * @ogm_cnt_lock: lock protecting bcast_own, bcast_own_sum,
+ *  neigh_node->real_bits & neigh_node->real_packet_count
+ * @bcast_seqno_lock: lock protecting bcast_bits & last_bcast_seqno
+ * @bond_candidates: how many candidates are available
+ * @bond_list: list of bonding candidates
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
  */
 struct batadv_orig_node {
        uint8_t orig[ETH_ALEN];
@@ -94,11 +143,11 @@ struct batadv_orig_node {
        unsigned long batman_seqno_reset;
        uint8_t gw_flags;
        uint8_t flags;
-       atomic_t last_ttvn; /* last seen translation table version number */
+       atomic_t last_ttvn;
        uint16_t tt_crc;
        unsigned char *tt_buff;
        int16_t tt_buff_len;
-       spinlock_t tt_buff_lock; /* protects tt_buff */
+       spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */
        atomic_t tt_size;
        bool tt_initialised;
        uint32_t last_real_seqno;
@@ -107,23 +156,31 @@ struct batadv_orig_node {
        uint32_t last_bcast_seqno;
        struct hlist_head neigh_list;
        struct list_head frag_list;
-       spinlock_t neigh_list_lock; /* protects neigh_list and router */
-       atomic_t refcount;
-       struct rcu_head rcu;
+       unsigned long last_frag_packet;
+       /* neigh_list_lock protects: neigh_list, router & bonding_list */
+       spinlock_t neigh_list_lock;
        struct hlist_node hash_entry;
        struct batadv_priv *bat_priv;
-       unsigned long last_frag_packet;
        /* ogm_cnt_lock protects: bcast_own, bcast_own_sum,
-        * neigh_node->real_bits, neigh_node->real_packet_count
+        * neigh_node->real_bits & neigh_node->real_packet_count
         */
        spinlock_t ogm_cnt_lock;
-       /* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */
+       /* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */
        spinlock_t bcast_seqno_lock;
-       spinlock_t tt_list_lock; /* protects tt_list */
        atomic_t bond_candidates;
        struct list_head bond_list;
+       atomic_t refcount;
+       struct rcu_head rcu;
 };
 
+/**
+ * struct batadv_gw_node - structure for orig nodes announcing gw capabilities
+ * @list: list node for batadv_priv_gw::list
+ * @orig_node: pointer to corresponding orig node
+ * @deleted: this struct is scheduled for deletion
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
 struct batadv_gw_node {
        struct hlist_node list;
        struct batadv_orig_node *orig_node;
@@ -132,13 +189,28 @@ struct batadv_gw_node {
        struct rcu_head rcu;
 };
 
-/*     batadv_neigh_node
- *     @last_seen: when last packet via this neighbor was received
+/**
+ * struct batadv_neigh_node - structure for single hop neighbors
+ * @list: list node for batadv_orig_node::neigh_list
+ * @addr: mac address of neigh node
+ * @tq_recv: ring buffer of received TQ values from this neigh node
+ * @tq_index: ring buffer index
+ * @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv)
+ * @last_ttl: last received ttl from this neigh node
+ * @bonding_list: list node for batadv_orig_node::bond_list
+ * @last_seen: when last packet via this neighbor was received
+ * @real_bits: bitfield containing the number of OGMs received from this neigh
+ *  node (relative to orig_node->last_real_seqno)
+ * @real_packet_count: counted result of real_bits
+ * @orig_node: pointer to corresponding orig_node
+ * @if_incoming: pointer to incoming hard interface
+ * @lq_update_lock: lock protecting tq_recv & tq_index
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
  */
 struct batadv_neigh_node {
        struct hlist_node list;
        uint8_t addr[ETH_ALEN];
-       uint8_t real_packet_count;
        uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE];
        uint8_t tq_index;
        uint8_t tq_avg;
@@ -146,13 +218,20 @@ struct batadv_neigh_node {
        struct list_head bonding_list;
        unsigned long last_seen;
        DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
-       atomic_t refcount;
-       struct rcu_head rcu;
+       uint8_t real_packet_count;
        struct batadv_orig_node *orig_node;
        struct batadv_hard_iface *if_incoming;
-       spinlock_t lq_update_lock;      /* protects: tq_recv, tq_index */
+       spinlock_t lq_update_lock; /* protects tq_recv & tq_index */
+       atomic_t refcount;
+       struct rcu_head rcu;
 };
 
+/**
+ * struct batadv_bcast_duplist_entry - structure for LAN broadcast suppression
+ * @orig[ETH_ALEN]: mac address of orig node orginating the broadcast
+ * @crc: crc32 checksum of broadcast payload
+ * @entrytime: time when the broadcast packet was received
+ */
 #ifdef CONFIG_BATMAN_ADV_BLA
 struct batadv_bcast_duplist_entry {
        uint8_t orig[ETH_ALEN];
@@ -161,6 +240,33 @@ struct batadv_bcast_duplist_entry {
 };
 #endif
 
+/**
+ * enum batadv_counters - indices for traffic counters
+ * @BATADV_CNT_TX: transmitted payload traffic packet counter
+ * @BATADV_CNT_TX_BYTES: transmitted payload traffic bytes counter
+ * @BATADV_CNT_TX_DROPPED: dropped transmission payload traffic packet counter
+ * @BATADV_CNT_RX: received payload traffic packet counter
+ * @BATADV_CNT_RX_BYTES: received payload traffic bytes counter
+ * @BATADV_CNT_FORWARD: forwarded payload traffic packet counter
+ * @BATADV_CNT_FORWARD_BYTES: forwarded payload traffic bytes counter
+ * @BATADV_CNT_MGMT_TX: transmitted routing protocol traffic packet counter
+ * @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter
+ * @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter
+ * @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter
+ * @BATADV_CNT_TT_REQUEST_TX: transmitted tt req traffic packet counter
+ * @BATADV_CNT_TT_REQUEST_RX: received tt req traffic packet counter
+ * @BATADV_CNT_TT_RESPONSE_TX: transmitted tt resp traffic packet counter
+ * @BATADV_CNT_TT_RESPONSE_RX: received tt resp traffic packet counter
+ * @BATADV_CNT_TT_ROAM_ADV_TX: transmitted tt roam traffic packet counter
+ * @BATADV_CNT_TT_ROAM_ADV_RX: received tt roam traffic packet counter
+ * @BATADV_CNT_DAT_GET_TX: transmitted dht GET traffic packet counter
+ * @BATADV_CNT_DAT_GET_RX: received dht GET traffic packet counter
+ * @BATADV_CNT_DAT_PUT_TX: transmitted dht PUT traffic packet counter
+ * @BATADV_CNT_DAT_PUT_RX: received dht PUT traffic packet counter
+ * @BATADV_CNT_DAT_CACHED_REPLY_TX: transmitted dat cache reply traffic packet
+ *  counter
+ * @BATADV_CNT_NUM: number of traffic counters
+ */
 enum batadv_counters {
        BATADV_CNT_TX,
        BATADV_CNT_TX_BYTES,
@@ -192,14 +298,23 @@ enum batadv_counters {
 /**
  * struct batadv_priv_tt - per mesh interface translation table data
  * @vn: translation table version number
+ * @ogm_append_cnt: counter of number of OGMs containing the local tt diff
  * @local_changes: changes registered in an originator interval
- * @poss_change: Detect an ongoing roaming phase. If true, then this node
- *  received a roaming_adv and has to inspect every packet directed to it to
- *  check whether it still is the true destination or not. This flag will be
- *  reset to false as soon as the this node's ttvn is increased
  * @changes_list: tracks tt local changes within an originator interval
- * @req_list: list of pending tt_requests
+ * @local_hash: local translation table hash table
+ * @global_hash: global translation table hash table
+ * @req_list: list of pending & unanswered tt_requests
+ * @roam_list: list of the last roaming events of each client limiting the
+ *  number of roaming events to avoid route flapping
+ * @changes_list_lock: lock protecting changes_list
+ * @req_list_lock: lock protecting req_list
+ * @roam_list_lock: lock protecting roam_list
+ * @local_entry_num: number of entries in the local hash table
  * @local_crc: Checksum of the local table, recomputed before sending a new OGM
+ * @last_changeset: last tt changeset this host has generated
+ * @last_changeset_len: length of last tt changeset this host has generated
+ * @last_changeset_lock: lock protecting last_changeset & last_changeset_len
+ * @work: work queue callback item for translation table purging
  */
 struct batadv_priv_tt {
        atomic_t vn;
@@ -217,36 +332,83 @@ struct batadv_priv_tt {
        uint16_t local_crc;
        unsigned char *last_changeset;
        int16_t last_changeset_len;
-       spinlock_t last_changeset_lock; /* protects last_changeset */
+       /* protects last_changeset & last_changeset_len */
+       spinlock_t last_changeset_lock;
        struct delayed_work work;
 };
 
+/**
+ * struct batadv_priv_bla - per mesh interface bridge loope avoidance data
+ * @num_requests; number of bla requests in flight
+ * @claim_hash: hash table containing mesh nodes this host has claimed
+ * @backbone_hash: hash table containing all detected backbone gateways
+ * @bcast_duplist: recently received broadcast packets array (for broadcast
+ *  duplicate suppression)
+ * @bcast_duplist_curr: index of last broadcast packet added to bcast_duplist
+ * @bcast_duplist_lock: lock protecting bcast_duplist & bcast_duplist_curr
+ * @claim_dest: local claim data (e.g. claim group)
+ * @work: work queue callback item for cleanups & bla announcements
+ */
 #ifdef CONFIG_BATMAN_ADV_BLA
 struct batadv_priv_bla {
-       atomic_t num_requests; /* number of bla requests in flight */
+       atomic_t num_requests;
        struct batadv_hashtable *claim_hash;
        struct batadv_hashtable *backbone_hash;
        struct batadv_bcast_duplist_entry bcast_duplist[BATADV_DUPLIST_SIZE];
        int bcast_duplist_curr;
-       /* protects bcast_duplist and bcast_duplist_curr */
+       /* protects bcast_duplist & bcast_duplist_curr */
        spinlock_t bcast_duplist_lock;
        struct batadv_bla_claim_dst claim_dest;
        struct delayed_work work;
 };
 #endif
 
+/**
+ * struct batadv_debug_log - debug logging data
+ * @log_buff: buffer holding the logs (ring bufer)
+ * @log_start: index of next character to read
+ * @log_end: index of next character to write
+ * @lock: lock protecting log_buff, log_start & log_end
+ * @queue_wait: log reader's wait queue
+ */
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+struct batadv_priv_debug_log {
+       char log_buff[BATADV_LOG_BUF_LEN];
+       unsigned long log_start;
+       unsigned long log_end;
+       spinlock_t lock; /* protects log_buff, log_start and log_end */
+       wait_queue_head_t queue_wait;
+};
+#endif
+
+/**
+ * struct batadv_priv_gw - per mesh interface gateway data
+ * @list: list of available gateway nodes
+ * @list_lock: lock protecting gw_list & curr_gw
+ * @curr_gw: pointer to currently selected gateway node
+ * @reselect: bool indicating a gateway re-selection is in progress
+ */
 struct batadv_priv_gw {
        struct hlist_head list;
-       spinlock_t list_lock; /* protects gw_list and curr_gw */
+       spinlock_t list_lock; /* protects gw_list & curr_gw */
        struct batadv_gw_node __rcu *curr_gw;  /* rcu protected pointer */
        atomic_t reselect;
 };
 
+/**
+ * struct batadv_priv_vis - per mesh interface vis data
+ * @send_list: list of batadv_vis_info packets to sent
+ * @hash: hash table containing vis data from other nodes in the network
+ * @hash_lock: lock protecting the hash table
+ * @list_lock: lock protecting my_info::recv_list
+ * @work: work queue callback item for vis packet sending
+ * @my_info: holds this node's vis data sent on a regular basis
+ */
 struct batadv_priv_vis {
        struct list_head send_list;
        struct batadv_hashtable *hash;
        spinlock_t hash_lock; /* protects hash */
-       spinlock_t list_lock; /* protects info::recv_list */
+       spinlock_t list_lock; /* protects my_info::recv_list */
        struct delayed_work work;
        struct batadv_vis_info *my_info;
 };
@@ -265,30 +427,78 @@ struct batadv_priv_dat {
 };
 #endif
 
+/**
+ * struct batadv_priv - per mesh interface data
+ * @mesh_state: current status of the mesh (inactive/active/deactivating)
+ * @soft_iface: net device which holds this struct as private data
+ * @stats: structure holding the data for the ndo_get_stats() call
+ * @bat_counters: mesh internal traffic statistic counters (see batadv_counters)
+ * @aggregated_ogms: bool indicating whether OGM aggregation is enabled
+ * @bonding: bool indicating whether traffic bonding is enabled
+ * @fragmentation: bool indicating whether traffic fragmentation is enabled
+ * @ap_isolation: bool indicating whether ap isolation is enabled
+ * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is
+ *  enabled
+ * @distributed_arp_table: bool indicating whether distributed ARP table is
+ *  enabled
+ * @vis_mode: vis operation: client or server (see batadv_vis_packettype)
+ * @gw_mode: gateway operation: off, client or server (see batadv_gw_modes)
+ * @gw_sel_class: gateway selection class (applies if gw_mode client)
+ * @gw_bandwidth: gateway announced bandwidth (applies if gw_mode server)
+ * @orig_interval: OGM broadcast interval in milliseconds
+ * @hop_penalty: penalty which will be applied to an OGM's tq-field on every hop
+ * @log_level: configured log level (see batadv_dbg_level)
+ * @bcast_seqno: last sent broadcast packet sequence number
+ * @bcast_queue_left: number of remaining buffered broadcast packet slots
+ * @batman_queue_left: number of remaining OGM packet slots
+ * @num_ifaces: number of interfaces assigned to this mesh interface
+ * @mesh_obj: kobject for sysfs mesh subdirectory
+ * @debug_dir: dentry for debugfs batman-adv subdirectory
+ * @forw_bat_list: list of aggregated OGMs that will be forwarded
+ * @forw_bcast_list: list of broadcast packets that will be rebroadcasted
+ * @orig_hash: hash table containing mesh participants (orig nodes)
+ * @forw_bat_list_lock: lock protecting forw_bat_list
+ * @forw_bcast_list_lock: lock protecting forw_bcast_list
+ * @orig_work: work queue callback item for orig node purging
+ * @cleanup_work: work queue callback item for soft interface deinit
+ * @primary_if: one of the hard interfaces assigned to this mesh interface
+ *  becomes the primary interface
+ * @bat_algo_ops: routing algorithm used by this mesh interface
+ * @bla: bridge loope avoidance data
+ * @debug_log: holding debug logging relevant data
+ * @gw: gateway data
+ * @tt: translation table data
+ * @vis: vis data
+ * @dat: distributed arp table data
+ */
 struct batadv_priv {
        atomic_t mesh_state;
+       struct net_device *soft_iface;
        struct net_device_stats stats;
        uint64_t __percpu *bat_counters; /* Per cpu counters */
-       atomic_t aggregated_ogms;       /* boolean */
-       atomic_t bonding;               /* boolean */
-       atomic_t fragmentation;         /* boolean */
-       atomic_t ap_isolation;          /* boolean */
-       atomic_t bridge_loop_avoidance; /* boolean */
+       atomic_t aggregated_ogms;
+       atomic_t bonding;
+       atomic_t fragmentation;
+       atomic_t ap_isolation;
+#ifdef CONFIG_BATMAN_ADV_BLA
+       atomic_t bridge_loop_avoidance;
+#endif
 #ifdef CONFIG_BATMAN_ADV_DAT
-       atomic_t distributed_arp_table; /* boolean */
+       atomic_t distributed_arp_table;
+#endif
+       atomic_t vis_mode;
+       atomic_t gw_mode;
+       atomic_t gw_sel_class;
+       atomic_t gw_bandwidth;
+       atomic_t orig_interval;
+       atomic_t hop_penalty;
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+       atomic_t log_level;
 #endif
-       atomic_t vis_mode;              /* VIS_TYPE_* */
-       atomic_t gw_mode;               /* GW_MODE_* */
-       atomic_t gw_sel_class;          /* uint */
-       atomic_t gw_bandwidth;          /* gw bandwidth */
-       atomic_t orig_interval;         /* uint */
-       atomic_t hop_penalty;           /* uint */
-       atomic_t log_level;             /* uint */
        atomic_t bcast_seqno;
        atomic_t bcast_queue_left;
        atomic_t batman_queue_left;
        char num_ifaces;
-       struct batadv_debug_log *debug_log;
        struct kobject *mesh_obj;
        struct dentry *debug_dir;
        struct hlist_head forw_bat_list;
@@ -297,10 +507,14 @@ struct batadv_priv {
        spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
        spinlock_t forw_bcast_list_lock; /* protects forw_bcast_list */
        struct delayed_work orig_work;
+       struct work_struct cleanup_work;
        struct batadv_hard_iface __rcu *primary_if;  /* rcu protected pointer */
        struct batadv_algo_ops *bat_algo_ops;
 #ifdef CONFIG_BATMAN_ADV_BLA
        struct batadv_priv_bla bla;
+#endif
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+       struct batadv_priv_debug_log *debug_log;
 #endif
        struct batadv_priv_gw gw;
        struct batadv_priv_tt tt;
@@ -310,21 +524,97 @@ struct batadv_priv {
 #endif
 };
 
+/**
+ * struct batadv_socket_client - layer2 icmp socket client data
+ * @queue_list: packet queue for packets destined for this socket client
+ * @queue_len: number of packets in the packet queue (queue_list)
+ * @index: socket client's index in the batadv_socket_client_hash
+ * @lock: lock protecting queue_list, queue_len & index
+ * @queue_wait: socket client's wait queue
+ * @bat_priv: pointer to soft_iface this client belongs to
+ */
 struct batadv_socket_client {
        struct list_head queue_list;
        unsigned int queue_len;
        unsigned char index;
-       spinlock_t lock; /* protects queue_list, queue_len, index */
+       spinlock_t lock; /* protects queue_list, queue_len & index */
        wait_queue_head_t queue_wait;
        struct batadv_priv *bat_priv;
 };
 
+/**
+ * struct batadv_socket_packet - layer2 icmp packet for socket client
+ * @list: list node for batadv_socket_client::queue_list
+ * @icmp_len: size of the layer2 icmp packet
+ * @icmp_packet: layer2 icmp packet
+ */
 struct batadv_socket_packet {
        struct list_head list;
        size_t icmp_len;
        struct batadv_icmp_packet_rr icmp_packet;
 };
 
+/**
+ * struct batadv_bla_backbone_gw - batman-adv gateway bridged into the LAN
+ * @orig: originator address of backbone node (mac address of primary iface)
+ * @vid: vlan id this gateway was detected on
+ * @hash_entry: hlist node for batadv_priv_bla::backbone_hash
+ * @bat_priv: pointer to soft_iface this backbone gateway belongs to
+ * @lasttime: last time we heard of this backbone gw
+ * @wait_periods: grace time for bridge forward delays and bla group forming at
+ *  bootup phase - no bcast traffic is formwared until it has elapsed
+ * @request_sent: if this bool is set to true we are out of sync with this
+ *  backbone gateway - no bcast traffic is formwared until the situation was
+ *  resolved
+ * @crc: crc16 checksum over all claims
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
+#ifdef CONFIG_BATMAN_ADV_BLA
+struct batadv_bla_backbone_gw {
+       uint8_t orig[ETH_ALEN];
+       short vid;
+       struct hlist_node hash_entry;
+       struct batadv_priv *bat_priv;
+       unsigned long lasttime;
+       atomic_t wait_periods;
+       atomic_t request_sent;
+       uint16_t crc;
+       atomic_t refcount;
+       struct rcu_head rcu;
+};
+
+/**
+ * struct batadv_bla_claim - claimed non-mesh client structure
+ * @addr: mac address of claimed non-mesh client
+ * @vid: vlan id this client was detected on
+ * @batadv_bla_backbone_gw: pointer to backbone gw claiming this client
+ * @lasttime: last time we heard of claim (locals only)
+ * @hash_entry: hlist node for batadv_priv_bla::claim_hash
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
+struct batadv_bla_claim {
+       uint8_t addr[ETH_ALEN];
+       short vid;
+       struct batadv_bla_backbone_gw *backbone_gw;
+       unsigned long lasttime;
+       struct hlist_node hash_entry;
+       struct rcu_head rcu;
+       atomic_t refcount;
+};
+#endif
+
+/**
+ * struct batadv_tt_common_entry - tt local & tt global common data
+ * @addr: mac address of non-mesh client
+ * @hash_entry: hlist node for batadv_priv_tt::local_hash or for
+ *  batadv_priv_tt::global_hash
+ * @flags: various state handling flags (see batadv_tt_client_flags)
+ * @added_at: timestamp used for purging stale tt common entries
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
 struct batadv_tt_common_entry {
        uint8_t addr[ETH_ALEN];
        struct hlist_node hash_entry;
@@ -334,62 +624,76 @@ struct batadv_tt_common_entry {
        struct rcu_head rcu;
 };
 
+/**
+ * struct batadv_tt_local_entry - translation table local entry data
+ * @common: general translation table data
+ * @last_seen: timestamp used for purging stale tt local entries
+ */
 struct batadv_tt_local_entry {
        struct batadv_tt_common_entry common;
        unsigned long last_seen;
 };
 
+/**
+ * struct batadv_tt_global_entry - translation table global entry data
+ * @common: general translation table data
+ * @orig_list: list of orig nodes announcing this non-mesh client
+ * @list_lock: lock protecting orig_list
+ * @roam_at: time at which TT_GLOBAL_ROAM was set
+ */
 struct batadv_tt_global_entry {
        struct batadv_tt_common_entry common;
        struct hlist_head orig_list;
-       spinlock_t list_lock;   /* protects the list */
-       unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
+       spinlock_t list_lock;   /* protects orig_list */
+       unsigned long roam_at;
 };
 
+/**
+ * struct batadv_tt_orig_list_entry - orig node announcing a non-mesh client
+ * @orig_node: pointer to orig node announcing this non-mesh client
+ * @ttvn: translation table version number which added the non-mesh client
+ * @list: list node for batadv_tt_global_entry::orig_list
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
 struct batadv_tt_orig_list_entry {
        struct batadv_orig_node *orig_node;
        uint8_t ttvn;
-       atomic_t refcount;
-       struct rcu_head rcu;
        struct hlist_node list;
-};
-
-#ifdef CONFIG_BATMAN_ADV_BLA
-struct batadv_backbone_gw {
-       uint8_t orig[ETH_ALEN];
-       short vid;              /* used VLAN ID */
-       struct hlist_node hash_entry;
-       struct batadv_priv *bat_priv;
-       unsigned long lasttime; /* last time we heard of this backbone gw */
-       atomic_t wait_periods;
-       atomic_t request_sent;
        atomic_t refcount;
        struct rcu_head rcu;
-       uint16_t crc;           /* crc checksum over all claims */
-};
-
-struct batadv_claim {
-       uint8_t addr[ETH_ALEN];
-       short vid;
-       struct batadv_backbone_gw *backbone_gw;
-       unsigned long lasttime; /* last time we heard of claim (locals only) */
-       struct rcu_head rcu;
-       atomic_t refcount;
-       struct hlist_node hash_entry;
 };
-#endif
 
+/**
+ * struct batadv_tt_change_node - structure for tt changes occured
+ * @list: list node for batadv_priv_tt::changes_list
+ * @change: holds the actual translation table diff data
+ */
 struct batadv_tt_change_node {
        struct list_head list;
        struct batadv_tt_change change;
 };
 
+/**
+ * struct batadv_tt_req_node - data to keep track of the tt requests in flight
+ * @addr: mac address address of the originator this request was sent to
+ * @issued_at: timestamp used for purging stale tt requests
+ * @list: list node for batadv_priv_tt::req_list
+ */
 struct batadv_tt_req_node {
        uint8_t addr[ETH_ALEN];
        unsigned long issued_at;
        struct list_head list;
 };
 
+/**
+ * struct batadv_tt_roam_node - roaming client data
+ * @addr: mac address of the client in the roaming phase
+ * @counter: number of allowed roaming events per client within a single
+ *  OGM interval (changes are committed with each OGM)
+ * @first_time: timestamp used for purging stale roaming node entries
+ * @list: list node for batadv_priv_tt::roam_list
+ */
 struct batadv_tt_roam_node {
        uint8_t addr[ETH_ALEN];
        atomic_t counter;
@@ -397,8 +701,19 @@ struct batadv_tt_roam_node {
        struct list_head list;
 };
 
-/*     forw_packet - structure for forw_list maintaining packets to be
- *                   send/forwarded
+/**
+ * struct batadv_forw_packet - structure for bcast packets to be sent/forwarded
+ * @list: list node for batadv_socket_client::queue_list
+ * @send_time: execution time for delayed_work (packet sending)
+ * @own: bool for locally generated packets (local OGMs are re-scheduled after
+ *  sending)
+ * @skb: bcast packet's skb buffer
+ * @packet_len: size of aggregated OGM packet inside the skb buffer
+ * @direct_link_flags: direct link flags for aggregated OGM packets
+ * @num_packets: counter for bcast packet retransmission
+ * @delayed_work: work queue callback item for packet sending
+ * @if_incoming: pointer incoming hard-iface or primary iface if locally
+ *  generated packet
  */
 struct batadv_forw_packet {
        struct hlist_node list;
@@ -412,72 +727,98 @@ struct batadv_forw_packet {
        struct batadv_hard_iface *if_incoming;
 };
 
-/* While scanning for vis-entries of a particular vis-originator
- * this list collects its interfaces to create a subgraph/cluster
- * out of them later
+/**
+ * struct batadv_frag_packet_list_entry - storage for fragment packet
+ * @list: list node for orig_node::frag_list
+ * @seqno: sequence number of the fragment
+ * @skb: fragment's skb buffer
  */
-struct batadv_if_list_entry {
-       uint8_t addr[ETH_ALEN];
-       bool primary;
-       struct hlist_node list;
-};
-
-struct batadv_debug_log {
-       char log_buff[BATADV_LOG_BUF_LEN];
-       unsigned long log_start;
-       unsigned long log_end;
-       spinlock_t lock; /* protects log_buff, log_start and log_end */
-       wait_queue_head_t queue_wait;
-};
-
 struct batadv_frag_packet_list_entry {
        struct list_head list;
        uint16_t seqno;
        struct sk_buff *skb;
 };
 
+/**
+ * struct batadv_vis_info - local data for vis information
+ * @first_seen: timestamp used for purging stale vis info entries
+ * @recv_list: List of server-neighbors we have received this packet from. This
+ *  packet should not be re-forward to them again. List elements are struct
+ *  batadv_vis_recvlist_node
+ * @send_list: list of packets to be forwarded
+ * @refcount: number of contexts the object is used
+ * @hash_entry: hlist node for batadv_priv_vis::hash
+ * @bat_priv: pointer to soft_iface this orig node belongs to
+ * @skb_packet: contains the vis packet
+ */
 struct batadv_vis_info {
        unsigned long first_seen;
-       /* list of server-neighbors we received a vis-packet
-        * from.  we should not reply to them.
-        */
        struct list_head recv_list;
        struct list_head send_list;
        struct kref refcount;
        struct hlist_node hash_entry;
        struct batadv_priv *bat_priv;
-       /* this packet might be part of the vis send queue. */
        struct sk_buff *skb_packet;
-       /* vis_info may follow here */
 } __packed;
 
+/**
+ * struct batadv_vis_info_entry - contains link information for vis
+ * @src: source MAC of the link, all zero for local TT entry
+ * @dst: destination MAC of the link, client mac address for local TT entry
+ * @quality: transmission quality of the link, or 0 for local TT entry
+ */
 struct batadv_vis_info_entry {
        uint8_t  src[ETH_ALEN];
        uint8_t  dest[ETH_ALEN];
-       uint8_t  quality;       /* quality = 0 client */
+       uint8_t  quality;
 } __packed;
 
-struct batadv_recvlist_node {
+/**
+ * struct batadv_vis_recvlist_node - list entry for batadv_vis_info::recv_list
+ * @list: list node for batadv_vis_info::recv_list
+ * @mac: MAC address of the originator from where the vis_info was received
+ */
+struct batadv_vis_recvlist_node {
        struct list_head list;
        uint8_t mac[ETH_ALEN];
 };
 
+/**
+ * struct batadv_vis_if_list_entry - auxiliary data for vis data generation
+ * @addr: MAC address of the interface
+ * @primary: true if this interface is the primary interface
+ * @list: list node the interface list
+ *
+ * While scanning for vis-entries of a particular vis-originator
+ * this list collects its interfaces to create a subgraph/cluster
+ * out of them later
+ */
+struct batadv_vis_if_list_entry {
+       uint8_t addr[ETH_ALEN];
+       bool primary;
+       struct hlist_node list;
+};
+
+/**
+ * struct batadv_algo_ops - mesh algorithm callbacks
+ * @list: list node for the batadv_algo_list
+ * @name: name of the algorithm
+ * @bat_iface_enable: init routing info when hard-interface is enabled
+ * @bat_iface_disable: de-init routing info when hard-interface is disabled
+ * @bat_iface_update_mac: (re-)init mac addresses of the protocol information
+ *  belonging to this hard-interface
+ * @bat_primary_iface_set: called when primary interface is selected / changed
+ * @bat_ogm_schedule: prepare a new outgoing OGM for the send queue
+ * @bat_ogm_emit: send scheduled OGM
+ */
 struct batadv_algo_ops {
        struct hlist_node list;
        char *name;
-       /* init routing info when hard-interface is enabled */
        int (*bat_iface_enable)(struct batadv_hard_iface *hard_iface);
-       /* de-init routing info when hard-interface is disabled */
        void (*bat_iface_disable)(struct batadv_hard_iface *hard_iface);
-       /* (re-)init mac addresses of the protocol information
-        * belonging to this hard-interface
-        */
        void (*bat_iface_update_mac)(struct batadv_hard_iface *hard_iface);
-       /* called when primary interface is selected / changed */
        void (*bat_primary_iface_set)(struct batadv_hard_iface *hard_iface);
-       /* prepare a new outgoing OGM for the send queue */
        void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface);
-       /* send scheduled OGM */
        void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet);
 };
 
index 10aff49fcf25adb106cefb020309e456d8f04a2f..50e079f00be62aeb7530a88d70edc42215dff743 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
  *
  * Andreas Langer
  *
@@ -133,7 +133,6 @@ batadv_frag_search_packet(struct list_head *head,
        is_head = !!(up->flags & BATADV_UNI_FRAG_HEAD);
 
        list_for_each_entry(tfp, head, list) {
-
                if (!tfp->skb)
                        continue;
 
@@ -162,7 +161,6 @@ void batadv_frag_list_free(struct list_head *head)
        struct batadv_frag_packet_list_entry *pf, *tmp_pf;
 
        if (!list_empty(head)) {
-
                list_for_each_entry_safe(pf, tmp_pf, head, list) {
                        kfree_skb(pf->skb);
                        list_del(&pf->list);
index 61abba58bd8fee1ac6be8b043927d52ddf9f141b..429cf8a4a31eb367f727d494af43077b10f12854 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
  *
  * Andreas Langer
  *
index 0f65a9de5f749719b9b778cd8c989680b0b1eb4d..22d2785177d15f63b8c853cc4a5910858b268f0b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
 
 #define BATADV_MAX_VIS_PACKET_SIZE 1000
 
-static void batadv_start_vis_timer(struct batadv_priv *bat_priv);
+/* hash class keys */
+static struct lock_class_key batadv_vis_hash_lock_class_key;
 
 /* free the info */
 static void batadv_free_info(struct kref *ref)
 {
        struct batadv_vis_info *info;
        struct batadv_priv *bat_priv;
-       struct batadv_recvlist_node *entry, *tmp;
+       struct batadv_vis_recvlist_node *entry, *tmp;
 
        info = container_of(ref, struct batadv_vis_info, refcount);
        bat_priv = info->bat_priv;
@@ -126,7 +127,7 @@ static void batadv_vis_data_insert_interface(const uint8_t *interface,
                                             struct hlist_head *if_list,
                                             bool primary)
 {
-       struct batadv_if_list_entry *entry;
+       struct batadv_vis_if_list_entry *entry;
        struct hlist_node *pos;
 
        hlist_for_each_entry(entry, pos, if_list, list) {
@@ -146,7 +147,7 @@ static void batadv_vis_data_insert_interface(const uint8_t *interface,
 static void batadv_vis_data_read_prim_sec(struct seq_file *seq,
                                          const struct hlist_head *if_list)
 {
-       struct batadv_if_list_entry *entry;
+       struct batadv_vis_if_list_entry *entry;
        struct hlist_node *pos;
 
        hlist_for_each_entry(entry, pos, if_list, list) {
@@ -196,7 +197,7 @@ static void batadv_vis_data_read_entries(struct seq_file *seq,
                                         struct batadv_vis_info_entry *entries)
 {
        int i;
-       struct batadv_if_list_entry *entry;
+       struct batadv_vis_if_list_entry *entry;
        struct hlist_node *pos;
 
        hlist_for_each_entry(entry, pos, list, list) {
@@ -222,7 +223,7 @@ static void batadv_vis_seq_print_text_bucket(struct seq_file *seq,
        struct batadv_vis_packet *packet;
        uint8_t *entries_pos;
        struct batadv_vis_info_entry *entries;
-       struct batadv_if_list_entry *entry;
+       struct batadv_vis_if_list_entry *entry;
        struct hlist_node *pos, *n;
 
        HLIST_HEAD(vis_if_list);
@@ -304,7 +305,7 @@ static void batadv_send_list_del(struct batadv_vis_info *info)
 static void batadv_recv_list_add(struct batadv_priv *bat_priv,
                                 struct list_head *recv_list, const char *mac)
 {
-       struct batadv_recvlist_node *entry;
+       struct batadv_vis_recvlist_node *entry;
 
        entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
        if (!entry)
@@ -321,7 +322,7 @@ static int batadv_recv_list_is_in(struct batadv_priv *bat_priv,
                                  const struct list_head *recv_list,
                                  const char *mac)
 {
-       const struct batadv_recvlist_node *entry;
+       const struct batadv_vis_recvlist_node *entry;
 
        spin_lock_bh(&bat_priv->vis.list_lock);
        list_for_each_entry(entry, recv_list, list) {
@@ -827,7 +828,9 @@ static void batadv_send_vis_packets(struct work_struct *work)
                kref_put(&info->refcount, batadv_free_info);
        }
        spin_unlock_bh(&bat_priv->vis.hash_lock);
-       batadv_start_vis_timer(bat_priv);
+
+       queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work,
+                          msecs_to_jiffies(BATADV_VIS_INTERVAL));
 }
 
 /* init the vis server. this may only be called when if_list is already
@@ -852,6 +855,9 @@ int batadv_vis_init(struct batadv_priv *bat_priv)
                goto err;
        }
 
+       batadv_hash_set_lock_class(bat_priv->vis.hash,
+                                  &batadv_vis_hash_lock_class_key);
+
        bat_priv->vis.my_info = kmalloc(BATADV_MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
        if (!bat_priv->vis.my_info)
                goto err;
@@ -894,7 +900,11 @@ int batadv_vis_init(struct batadv_priv *bat_priv)
        }
 
        spin_unlock_bh(&bat_priv->vis.hash_lock);
-       batadv_start_vis_timer(bat_priv);
+
+       INIT_DELAYED_WORK(&bat_priv->vis.work, batadv_send_vis_packets);
+       queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work,
+                          msecs_to_jiffies(BATADV_VIS_INTERVAL));
+
        return 0;
 
 free_info:
@@ -931,11 +941,3 @@ void batadv_vis_quit(struct batadv_priv *bat_priv)
        bat_priv->vis.my_info = NULL;
        spin_unlock_bh(&bat_priv->vis.hash_lock);
 }
-
-/* schedule packets for (re)transmission */
-static void batadv_start_vis_timer(struct batadv_priv *bat_priv)
-{
-       INIT_DELAYED_WORK(&bat_priv->vis.work, batadv_send_vis_packets);
-       queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work,
-                          msecs_to_jiffies(BATADV_VIS_INTERVAL));
-}
index 873282fa86dadce0671c1c928a44903229462543..ad92b0e3c230de211bfd2aca90f1c9431bc1b9c1 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008-2012 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
index 7c78e264019000fe48d4bed8c22a86f6b7b4131d..e1bc090bc00acb160ead451894cf045b59ba386e 100644 (file)
@@ -172,7 +172,6 @@ static int br_set_mac_address(struct net_device *dev, void *p)
 
        spin_lock_bh(&br->lock);
        if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) {
-               dev->addr_assign_type &= ~NET_ADDR_RANDOM;
                memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
                br_fdb_change_mac_address(br, addr->sa_data);
                br_stp_change_bridge_id(br, addr->sa_data);
@@ -185,10 +184,10 @@ static int br_set_mac_address(struct net_device *dev, void *p)
 
 static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "bridge");
-       strcpy(info->version, BR_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, "N/A");
+       strlcpy(info->driver, "bridge", sizeof(info->driver));
+       strlcpy(info->version, BR_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
 }
 
 static netdev_features_t br_fix_features(struct net_device *dev,
index 37fe693471a84d6815b31a5efcadfd836c0be254..2148d474a04fa1a2b585c07714320668b04aa1a0 100644 (file)
@@ -66,14 +66,14 @@ void br_port_carrier_check(struct net_bridge_port *p)
        struct net_device *dev = p->dev;
        struct net_bridge *br = p->br;
 
-       if (netif_running(dev) && netif_carrier_ok(dev))
+       if (netif_running(dev) && netif_oper_up(dev))
                p->path_cost = port_cost(dev);
 
        if (!netif_running(br->dev))
                return;
 
        spin_lock_bh(&br->lock);
-       if (netif_running(dev) && netif_carrier_ok(dev)) {
+       if (netif_running(dev) && netif_oper_up(dev)) {
                if (p->state == BR_STATE_DISABLED)
                        br_stp_enable_port(p);
        } else {
@@ -148,7 +148,7 @@ static void del_nbp(struct net_bridge_port *p)
        netdev_rx_handler_unregister(dev);
        synchronize_net();
 
-       netdev_set_master(dev, NULL);
+       netdev_upper_dev_unlink(dev, br->dev);
 
        br_multicast_del_port(p);
 
@@ -364,7 +364,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (br_netpoll_info(br) && ((err = br_netpoll_enable(p, GFP_KERNEL))))
                goto err3;
 
-       err = netdev_set_master(dev, br->dev);
+       err = netdev_master_upper_dev_link(dev, br->dev);
        if (err)
                goto err4;
 
@@ -383,7 +383,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        spin_lock_bh(&br->lock);
        changed_addr = br_stp_recalculate_bridge_id(br);
 
-       if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
+       if (netif_running(dev) && netif_oper_up(dev) &&
            (br->dev->flags & IFF_UP))
                br_stp_enable_port(p);
        spin_unlock_bh(&br->lock);
@@ -403,7 +403,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        return 0;
 
 err5:
-       netdev_set_master(dev, NULL);
+       netdev_upper_dev_unlink(dev, br->dev);
 err4:
        br_netpoll_disable(p);
 err3:
index 5dc66abcc9e22c93bb4f70f5a219f730bab63275..39ca9796f3f7a4cfe9c9be437749fbda939d5152 100644 (file)
@@ -181,8 +181,11 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state)
        if (p->br->stp_enabled == BR_KERNEL_STP)
                return -EBUSY;
 
+       /* if device is not up, change is not allowed
+        * if link is not present, only allowable state is disabled
+        */
        if (!netif_running(p->dev) ||
-           (!netif_carrier_ok(p->dev) && state != BR_STATE_DISABLED))
+           (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED))
                return -ENETDOWN;
 
        p->state = state;
index a76b62135558a06308cc76adff65de3d704d76bf..1644b3e1f947a554f944b3e6cf655a0346d7dc66 100644 (file)
@@ -82,7 +82,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
                break;
 
        case NETDEV_UP:
-               if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) {
+               if (netif_running(br->dev) && netif_oper_up(dev)) {
                        spin_lock_bh(&br->lock);
                        br_stp_enable_port(p);
                        spin_unlock_bh(&br->lock);
index 9d5a414a3943af23b08734c32685c10cb078c025..7b5197c7de1324a59a8563a1632652ec25403159 100644 (file)
@@ -54,7 +54,7 @@ void br_stp_enable_bridge(struct net_bridge *br)
        br_config_bpdu_generation(br);
 
        list_for_each_entry(p, &br->port_list, list) {
-               if ((p->dev->flags & IFF_UP) && netif_carrier_ok(p->dev))
+               if (netif_running(p->dev) && netif_oper_up(p->dev))
                        br_stp_enable_port(p);
 
        }
index 03200699d274bf5e156db6948ac47fb73664f0e8..a15c0e0d1fc777889cbec22c94197963b834f9fc 100644 (file)
@@ -16,10 +16,11 @@ menuconfig CAN
          If you want CAN support you should say Y here and also to the
          specific driver for your controller(s) below.
 
+if CAN
+
 config CAN_RAW
        tristate "Raw CAN Protocol (raw access with CAN-ID filtering)"
-       depends on CAN
-       default N
+       default y
        ---help---
          The raw CAN protocol option offers access to the CAN bus via
          the BSD socket API. You probably want to use the raw socket in
@@ -29,8 +30,7 @@ config CAN_RAW
 
 config CAN_BCM
        tristate "Broadcast Manager CAN Protocol (with content filtering)"
-       depends on CAN
-       default N
+       default y
        ---help---
          The Broadcast Manager offers content filtering, timeout monitoring,
          sending of RTR frames, and cyclic CAN messages without permanent user
@@ -42,8 +42,7 @@ config CAN_BCM
 
 config CAN_GW
        tristate "CAN Gateway/Router (with netlink configuration)"
-       depends on CAN
-       default N
+       default y
        ---help---
          The CAN Gateway/Router is used to route (and modify) CAN frames.
          It is based on the PF_CAN core infrastructure for msg filtering and
@@ -53,3 +52,5 @@ config CAN_GW
          by the netlink configuration interface known e.g. from iptables.
 
 source "drivers/net/can/Kconfig"
+
+endif
index 969b7cdff59d9480e4a7a77cbff72acb0e12eae7..28e12d18f0f147b592ee5e4975f4cecf3c5b7c2f 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/skbuff.h>
 #include <linux/can.h>
 #include <linux/can/core.h>
+#include <linux/can/skb.h>
 #include <linux/can/bcm.h>
 #include <linux/slab.h>
 #include <net/sock.h>
@@ -256,10 +257,13 @@ static void bcm_can_tx(struct bcm_op *op)
                return;
        }
 
-       skb = alloc_skb(CFSIZ, gfp_any());
+       skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), gfp_any());
        if (!skb)
                goto out;
 
+       can_skb_reserve(skb);
+       can_skb_prv(skb)->ifindex = dev->ifindex;
+
        memcpy(skb_put(skb, CFSIZ), cf, CFSIZ);
 
        /* send with loopback */
@@ -1199,11 +1203,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
        if (!ifindex)
                return -ENODEV;
 
-       skb = alloc_skb(CFSIZ, GFP_KERNEL);
-
+       skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), GFP_KERNEL);
        if (!skb)
                return -ENOMEM;
 
+       can_skb_reserve(skb);
+
        err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ);
        if (err < 0) {
                kfree_skb(skb);
@@ -1216,6 +1221,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
                return -ENODEV;
        }
 
+       can_skb_prv(skb)->ifindex = dev->ifindex;
        skb->dev = dev;
        skb->sk  = sk;
        err = can_send(skb, 1); /* send with loopback */
index 574dda78eb0f0d747eeeb44fb9da74be9618068f..c185fcd5e828b5b7fe0dddd9db237b2f172b50c9 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
 #include <linux/skbuff.h>
 #include <linux/can.h>
 #include <linux/can/core.h>
+#include <linux/can/skb.h>
 #include <linux/can/gw.h>
 #include <net/rtnetlink.h>
 #include <net/net_namespace.h>
 #include <net/sock.h>
 
-#define CAN_GW_VERSION "20101209"
-static __initconst const char banner[] =
-       KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
+#define CAN_GW_VERSION "20130117"
+#define CAN_GW_NAME "can-gw"
 
 MODULE_DESCRIPTION("PF_CAN netlink gateway");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
-MODULE_ALIAS("can-gw");
+MODULE_ALIAS(CAN_GW_NAME);
+
+#define CGW_MIN_HOPS 1
+#define CGW_MAX_HOPS 6
+#define CGW_DEFAULT_HOPS 1
+
+static unsigned int max_hops __read_mostly = CGW_DEFAULT_HOPS;
+module_param(max_hops, uint, S_IRUGO);
+MODULE_PARM_DESC(max_hops,
+                "maximum " CAN_GW_NAME " routing hops for CAN frames "
+                "(valid values: " __stringify(CGW_MIN_HOPS) "-"
+                __stringify(CGW_MAX_HOPS) " hops, "
+                "default: " __stringify(CGW_DEFAULT_HOPS) ")");
 
 static HLIST_HEAD(cgw_list);
 static struct notifier_block notifier;
@@ -118,6 +131,7 @@ struct cgw_job {
        struct rcu_head rcu;
        u32 handled_frames;
        u32 dropped_frames;
+       u32 deleted_frames;
        struct cf_mod mod;
        union {
                /* CAN frame data source */
@@ -338,15 +352,38 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
        struct sk_buff *nskb;
        int modidx = 0;
 
-       /* do not handle already routed frames - see comment below */
-       if (skb_mac_header_was_set(skb))
+       /*
+        * Do not handle CAN frames routed more than 'max_hops' times.
+        * In general we should never catch this delimiter which is intended
+        * to cover a misconfiguration protection (e.g. circular CAN routes).
+        *
+        * The Controller Area Network controllers only accept CAN frames with
+        * correct CRCs - which are not visible in the controller registers.
+        * According to skbuff.h documentation the csum_start element for IP
+        * checksums is undefined/unsued when ip_summed == CHECKSUM_UNNECESSARY.
+        * Only CAN skbs can be processed here which already have this property.
+        */
+
+#define cgw_hops(skb) ((skb)->csum_start)
+
+       BUG_ON(skb->ip_summed != CHECKSUM_UNNECESSARY);
+
+       if (cgw_hops(skb) >= max_hops) {
+               /* indicate deleted frames due to misconfiguration */
+               gwj->deleted_frames++;
                return;
+       }
 
        if (!(gwj->dst.dev->flags & IFF_UP)) {
                gwj->dropped_frames++;
                return;
        }
 
+       /* is sending the skb back to the incoming interface not allowed? */
+       if (!(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK) &&
+           can_skb_prv(skb)->ifindex == gwj->dst.dev->ifindex)
+               return;
+
        /*
         * clone the given skb, which has not been done in can_rcv()
         *
@@ -363,15 +400,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
                return;
        }
 
-       /*
-        * Mark routed frames by setting some mac header length which is
-        * not relevant for the CAN frames located in the skb->data section.
-        *
-        * As dev->header_ops is not set in CAN netdevices no one is ever
-        * accessing the various header offsets in the CAN skbuffs anyway.
-        * E.g. using the packet socket to read CAN frames is still working.
-        */
-       skb_set_mac_header(nskb, 8);
+       /* put the incremented hop counter in the cloned skb */
+       cgw_hops(nskb) = cgw_hops(skb) + 1;
        nskb->dev = gwj->dst.dev;
 
        /* pointer to modifiable CAN frame */
@@ -472,6 +502,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
                        goto cancel;
        }
 
+       if (gwj->deleted_frames) {
+               if (nla_put_u32(skb, CGW_DELETED, gwj->deleted_frames) < 0)
+                       goto cancel;
+       }
+
        /* check non default settings of attributes */
 
        if (gwj->mod.modtype.and) {
@@ -771,6 +806,7 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh,
 
        gwj->handled_frames = 0;
        gwj->dropped_frames = 0;
+       gwj->deleted_frames = 0;
        gwj->flags = r->flags;
        gwj->gwtype = r->gwtype;
 
@@ -895,7 +931,11 @@ static int cgw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
 
 static __init int cgw_module_init(void)
 {
-       printk(banner);
+       /* sanitize given module parameter */
+       max_hops = clamp_t(unsigned int, max_hops, CGW_MIN_HOPS, CGW_MAX_HOPS);
+
+       pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
+               max_hops);
 
        cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
                                      0, 0, NULL);
index 5b0e3e330d97c6f4172bf52db70a4cee6b7f4247..c1764e41ddaf924fed4e31972b938a84bb87b6f7 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/skbuff.h>
 #include <linux/can.h>
 #include <linux/can/core.h>
+#include <linux/can/skb.h>
 #include <linux/can/raw.h>
 #include <net/sock.h>
 #include <net/net_namespace.h>
@@ -699,11 +700,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
        if (!dev)
                return -ENXIO;
 
-       skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
-                                 &err);
+       skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv),
+                                 msg->msg_flags & MSG_DONTWAIT, &err);
        if (!skb)
                goto put_dev;
 
+       can_skb_reserve(skb);
+       can_skb_prv(skb)->ifindex = dev->ifindex;
+
        err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
        if (err < 0)
                goto free_skb;
index f64e439b4a00fe206fb634745a470475eb31cbb9..a83375d3af72eb29e9939016666a0c6e745b8fdd 100644 (file)
 #include <linux/cpu_rmap.h>
 #include <linux/net_tstamp.h>
 #include <linux/static_key.h>
-#include <net/flow_keys.h>
 
 #include "net-sysfs.h"
 
@@ -1857,6 +1856,228 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq)
        }
 }
 
+#ifdef CONFIG_XPS
+static DEFINE_MUTEX(xps_map_mutex);
+#define xmap_dereference(P)            \
+       rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex))
+
+static struct xps_map *remove_xps_queue(struct xps_dev_maps *dev_maps,
+                                       int cpu, u16 index)
+{
+       struct xps_map *map = NULL;
+       int pos;
+
+       if (dev_maps)
+               map = xmap_dereference(dev_maps->cpu_map[cpu]);
+
+       for (pos = 0; map && pos < map->len; pos++) {
+               if (map->queues[pos] == index) {
+                       if (map->len > 1) {
+                               map->queues[pos] = map->queues[--map->len];
+                       } else {
+                               RCU_INIT_POINTER(dev_maps->cpu_map[cpu], NULL);
+                               kfree_rcu(map, rcu);
+                               map = NULL;
+                       }
+                       break;
+               }
+       }
+
+       return map;
+}
+
+static void netif_reset_xps_queues_gt(struct net_device *dev, u16 index)
+{
+       struct xps_dev_maps *dev_maps;
+       int cpu, i;
+       bool active = false;
+
+       mutex_lock(&xps_map_mutex);
+       dev_maps = xmap_dereference(dev->xps_maps);
+
+       if (!dev_maps)
+               goto out_no_maps;
+
+       for_each_possible_cpu(cpu) {
+               for (i = index; i < dev->num_tx_queues; i++) {
+                       if (!remove_xps_queue(dev_maps, cpu, i))
+                               break;
+               }
+               if (i == dev->num_tx_queues)
+                       active = true;
+       }
+
+       if (!active) {
+               RCU_INIT_POINTER(dev->xps_maps, NULL);
+               kfree_rcu(dev_maps, rcu);
+       }
+
+       for (i = index; i < dev->num_tx_queues; i++)
+               netdev_queue_numa_node_write(netdev_get_tx_queue(dev, i),
+                                            NUMA_NO_NODE);
+
+out_no_maps:
+       mutex_unlock(&xps_map_mutex);
+}
+
+static struct xps_map *expand_xps_map(struct xps_map *map,
+                                     int cpu, u16 index)
+{
+       struct xps_map *new_map;
+       int alloc_len = XPS_MIN_MAP_ALLOC;
+       int i, pos;
+
+       for (pos = 0; map && pos < map->len; pos++) {
+               if (map->queues[pos] != index)
+                       continue;
+               return map;
+       }
+
+       /* Need to add queue to this CPU's existing map */
+       if (map) {
+               if (pos < map->alloc_len)
+                       return map;
+
+               alloc_len = map->alloc_len * 2;
+       }
+
+       /* Need to allocate new map to store queue on this CPU's map */
+       new_map = kzalloc_node(XPS_MAP_SIZE(alloc_len), GFP_KERNEL,
+                              cpu_to_node(cpu));
+       if (!new_map)
+               return NULL;
+
+       for (i = 0; i < pos; i++)
+               new_map->queues[i] = map->queues[i];
+       new_map->alloc_len = alloc_len;
+       new_map->len = pos;
+
+       return new_map;
+}
+
+int netif_set_xps_queue(struct net_device *dev, struct cpumask *mask, u16 index)
+{
+       struct xps_dev_maps *dev_maps, *new_dev_maps = NULL;
+       struct xps_map *map, *new_map;
+       int maps_sz = max_t(unsigned int, XPS_DEV_MAPS_SIZE, L1_CACHE_BYTES);
+       int cpu, numa_node_id = -2;
+       bool active = false;
+
+       mutex_lock(&xps_map_mutex);
+
+       dev_maps = xmap_dereference(dev->xps_maps);
+
+       /* allocate memory for queue storage */
+       for_each_online_cpu(cpu) {
+               if (!cpumask_test_cpu(cpu, mask))
+                       continue;
+
+               if (!new_dev_maps)
+                       new_dev_maps = kzalloc(maps_sz, GFP_KERNEL);
+               if (!new_dev_maps)
+                       return -ENOMEM;
+
+               map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) :
+                                NULL;
+
+               map = expand_xps_map(map, cpu, index);
+               if (!map)
+                       goto error;
+
+               RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map);
+       }
+
+       if (!new_dev_maps)
+               goto out_no_new_maps;
+
+       for_each_possible_cpu(cpu) {
+               if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu)) {
+                       /* add queue to CPU maps */
+                       int pos = 0;
+
+                       map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
+                       while ((pos < map->len) && (map->queues[pos] != index))
+                               pos++;
+
+                       if (pos == map->len)
+                               map->queues[map->len++] = index;
+#ifdef CONFIG_NUMA
+                       if (numa_node_id == -2)
+                               numa_node_id = cpu_to_node(cpu);
+                       else if (numa_node_id != cpu_to_node(cpu))
+                               numa_node_id = -1;
+#endif
+               } else if (dev_maps) {
+                       /* fill in the new device map from the old device map */
+                       map = xmap_dereference(dev_maps->cpu_map[cpu]);
+                       RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map);
+               }
+
+       }
+
+       rcu_assign_pointer(dev->xps_maps, new_dev_maps);
+
+       /* Cleanup old maps */
+       if (dev_maps) {
+               for_each_possible_cpu(cpu) {
+                       new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
+                       map = xmap_dereference(dev_maps->cpu_map[cpu]);
+                       if (map && map != new_map)
+                               kfree_rcu(map, rcu);
+               }
+
+               kfree_rcu(dev_maps, rcu);
+       }
+
+       dev_maps = new_dev_maps;
+       active = true;
+
+out_no_new_maps:
+       /* update Tx queue numa node */
+       netdev_queue_numa_node_write(netdev_get_tx_queue(dev, index),
+                                    (numa_node_id >= 0) ? numa_node_id :
+                                    NUMA_NO_NODE);
+
+       if (!dev_maps)
+               goto out_no_maps;
+
+       /* removes queue from unused CPUs */
+       for_each_possible_cpu(cpu) {
+               if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu))
+                       continue;
+
+               if (remove_xps_queue(dev_maps, cpu, index))
+                       active = true;
+       }
+
+       /* free map if not active */
+       if (!active) {
+               RCU_INIT_POINTER(dev->xps_maps, NULL);
+               kfree_rcu(dev_maps, rcu);
+       }
+
+out_no_maps:
+       mutex_unlock(&xps_map_mutex);
+
+       return 0;
+error:
+       /* remove any maps that we added */
+       for_each_possible_cpu(cpu) {
+               new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
+               map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) :
+                                NULL;
+               if (new_map && new_map != map)
+                       kfree(new_map);
+       }
+
+       mutex_unlock(&xps_map_mutex);
+
+       kfree(new_dev_maps);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(netif_set_xps_queue);
+
+#endif
 /*
  * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
  * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
@@ -1880,8 +2101,12 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
                if (dev->num_tc)
                        netif_setup_tc(dev, txq);
 
-               if (txq < dev->real_num_tx_queues)
+               if (txq < dev->real_num_tx_queues) {
                        qdisc_reset_all_tx_gt(dev, txq);
+#ifdef CONFIG_XPS
+                       netif_reset_xps_queues_gt(dev, txq);
+#endif
+               }
        }
 
        dev->real_num_tx_queues = txq;
@@ -2046,6 +2271,15 @@ int skb_checksum_help(struct sk_buff *skb)
                return -EINVAL;
        }
 
+       /* Before computing a checksum, we should make sure no frag could
+        * be modified by an external entity : checksum could be wrong.
+        */
+       if (skb_has_shared_frag(skb)) {
+               ret = __skb_linearize(skb);
+               if (ret)
+                       goto out;
+       }
+
        offset = skb_checksum_start_offset(skb);
        BUG_ON(offset >= skb_headlen(skb));
        csum = skb_checksum(skb, offset, skb->len - offset, 0);
@@ -2410,126 +2644,28 @@ out:
        return rc;
 }
 
-static u32 hashrnd __read_mostly;
-
-/*
- * Returns a Tx hash based on the given packet descriptor a Tx queues' number
- * to be used as a distribution range.
- */
-u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb,
-                 unsigned int num_tx_queues)
-{
-       u32 hash;
-       u16 qoffset = 0;
-       u16 qcount = num_tx_queues;
-
-       if (skb_rx_queue_recorded(skb)) {
-               hash = skb_get_rx_queue(skb);
-               while (unlikely(hash >= num_tx_queues))
-                       hash -= num_tx_queues;
-               return hash;
-       }
-
-       if (dev->num_tc) {
-               u8 tc = netdev_get_prio_tc_map(dev, skb->priority);
-               qoffset = dev->tc_to_txq[tc].offset;
-               qcount = dev->tc_to_txq[tc].count;
-       }
-
-       if (skb->sk && skb->sk->sk_hash)
-               hash = skb->sk->sk_hash;
-       else
-               hash = (__force u16) skb->protocol;
-       hash = jhash_1word(hash, hashrnd);
-
-       return (u16) (((u64) hash * qcount) >> 32) + qoffset;
-}
-EXPORT_SYMBOL(__skb_tx_hash);
-
-static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
+static void qdisc_pkt_len_init(struct sk_buff *skb)
 {
-       if (unlikely(queue_index >= dev->real_num_tx_queues)) {
-               net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n",
-                                    dev->name, queue_index,
-                                    dev->real_num_tx_queues);
-               return 0;
-       }
-       return queue_index;
-}
-
-static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
-{
-#ifdef CONFIG_XPS
-       struct xps_dev_maps *dev_maps;
-       struct xps_map *map;
-       int queue_index = -1;
+       const struct skb_shared_info *shinfo = skb_shinfo(skb);
 
-       rcu_read_lock();
-       dev_maps = rcu_dereference(dev->xps_maps);
-       if (dev_maps) {
-               map = rcu_dereference(
-                   dev_maps->cpu_map[raw_smp_processor_id()]);
-               if (map) {
-                       if (map->len == 1)
-                               queue_index = map->queues[0];
-                       else {
-                               u32 hash;
-                               if (skb->sk && skb->sk->sk_hash)
-                                       hash = skb->sk->sk_hash;
-                               else
-                                       hash = (__force u16) skb->protocol ^
-                                           skb->rxhash;
-                               hash = jhash_1word(hash, hashrnd);
-                               queue_index = map->queues[
-                                   ((u64)hash * map->len) >> 32];
-                       }
-                       if (unlikely(queue_index >= dev->real_num_tx_queues))
-                               queue_index = -1;
-               }
-       }
-       rcu_read_unlock();
-
-       return queue_index;
-#else
-       return -1;
-#endif
-}
-
-struct netdev_queue *netdev_pick_tx(struct net_device *dev,
-                                   struct sk_buff *skb)
-{
-       int queue_index;
-       const struct net_device_ops *ops = dev->netdev_ops;
-
-       if (dev->real_num_tx_queues == 1)
-               queue_index = 0;
-       else if (ops->ndo_select_queue) {
-               queue_index = ops->ndo_select_queue(dev, skb);
-               queue_index = dev_cap_txqueue(dev, queue_index);
-       } else {
-               struct sock *sk = skb->sk;
-               queue_index = sk_tx_queue_get(sk);
-
-               if (queue_index < 0 || skb->ooo_okay ||
-                   queue_index >= dev->real_num_tx_queues) {
-                       int old_index = queue_index;
+       qdisc_skb_cb(skb)->pkt_len = skb->len;
 
-                       queue_index = get_xps_queue(dev, skb);
-                       if (queue_index < 0)
-                               queue_index = skb_tx_hash(dev, skb);
+       /* To get more precise estimation of bytes sent on wire,
+        * we add to pkt_len the headers size of all segments
+        */
+       if (shinfo->gso_size)  {
+               unsigned int hdr_len;
 
-                       if (queue_index != old_index && sk) {
-                               struct dst_entry *dst =
-                                   rcu_dereference_check(sk->sk_dst_cache, 1);
+               /* mac layer + network layer */
+               hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
 
-                               if (dst && skb_dst(skb) == dst)
-                                       sk_tx_queue_set(sk, queue_index);
-                       }
-               }
+               /* + transport layer */
+               if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
+                       hdr_len += tcp_hdrlen(skb);
+               else
+                       hdr_len += sizeof(struct udphdr);
+               qdisc_skb_cb(skb)->pkt_len += (shinfo->gso_segs - 1) * hdr_len;
        }
-
-       skb_set_queue_mapping(skb, queue_index);
-       return netdev_get_tx_queue(dev, queue_index);
 }
 
 static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
@@ -2540,7 +2676,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
        bool contended;
        int rc;
 
-       qdisc_skb_cb(skb)->pkt_len = skb->len;
+       qdisc_pkt_len_init(skb);
        qdisc_calculate_pkt_len(skb, q);
        /*
         * Heuristic to force contended enqueues to serialize on a
@@ -2757,41 +2893,6 @@ static inline void ____napi_schedule(struct softnet_data *sd,
        __raise_softirq_irqoff(NET_RX_SOFTIRQ);
 }
 
-/*
- * __skb_get_rxhash: calculate a flow hash based on src/dst addresses
- * and src/dst port numbers.  Sets rxhash in skb to non-zero hash value
- * on success, zero indicates no valid hash.  Also, sets l4_rxhash in skb
- * if hash is a canonical 4-tuple hash over transport ports.
- */
-void __skb_get_rxhash(struct sk_buff *skb)
-{
-       struct flow_keys keys;
-       u32 hash;
-
-       if (!skb_flow_dissect(skb, &keys))
-               return;
-
-       if (keys.ports)
-               skb->l4_rxhash = 1;
-
-       /* get a consistent hash (same value on both flow directions) */
-       if (((__force u32)keys.dst < (__force u32)keys.src) ||
-           (((__force u32)keys.dst == (__force u32)keys.src) &&
-            ((__force u16)keys.port16[1] < (__force u16)keys.port16[0]))) {
-               swap(keys.dst, keys.src);
-               swap(keys.port16[0], keys.port16[1]);
-       }
-
-       hash = jhash_3words((__force u32)keys.dst,
-                           (__force u32)keys.src,
-                           (__force u32)keys.ports, hashrnd);
-       if (!hash)
-               hash = 1;
-
-       skb->rxhash = hash;
-}
-EXPORT_SYMBOL(__skb_get_rxhash);
-
 #ifdef CONFIG_RPS
 
 /* One global table that all flow-based protocols share. */
@@ -3352,7 +3453,8 @@ static int __netif_receive_skb(struct sk_buff *skb)
        orig_dev = skb->dev;
 
        skb_reset_network_header(skb);
-       skb_reset_transport_header(skb);
+       if (!skb_transport_header_was_set(skb))
+               skb_reset_transport_header(skb);
        skb_reset_mac_len(skb);
 
        pt_prev = NULL;
@@ -4600,64 +4702,231 @@ static int __init dev_proc_init(void)
 #endif /* CONFIG_PROC_FS */
 
 
+struct netdev_upper {
+       struct net_device *dev;
+       bool master;
+       struct list_head list;
+       struct rcu_head rcu;
+       struct list_head search_list;
+};
+
+static void __append_search_uppers(struct list_head *search_list,
+                                  struct net_device *dev)
+{
+       struct netdev_upper *upper;
+
+       list_for_each_entry(upper, &dev->upper_dev_list, list) {
+               /* check if this upper is not already in search list */
+               if (list_empty(&upper->search_list))
+                       list_add_tail(&upper->search_list, search_list);
+       }
+}
+
+static bool __netdev_search_upper_dev(struct net_device *dev,
+                                     struct net_device *upper_dev)
+{
+       LIST_HEAD(search_list);
+       struct netdev_upper *upper;
+       struct netdev_upper *tmp;
+       bool ret = false;
+
+       __append_search_uppers(&search_list, dev);
+       list_for_each_entry(upper, &search_list, search_list) {
+               if (upper->dev == upper_dev) {
+                       ret = true;
+                       break;
+               }
+               __append_search_uppers(&search_list, upper->dev);
+       }
+       list_for_each_entry_safe(upper, tmp, &search_list, search_list)
+               INIT_LIST_HEAD(&upper->search_list);
+       return ret;
+}
+
+static struct netdev_upper *__netdev_find_upper(struct net_device *dev,
+                                               struct net_device *upper_dev)
+{
+       struct netdev_upper *upper;
+
+       list_for_each_entry(upper, &dev->upper_dev_list, list) {
+               if (upper->dev == upper_dev)
+                       return upper;
+       }
+       return NULL;
+}
+
 /**
- *     netdev_set_master       -       set up master pointer
- *     @slave: slave device
- *     @master: new master device
- *
- *     Changes the master device of the slave. Pass %NULL to break the
- *     bonding. The caller must hold the RTNL semaphore. On a failure
- *     a negative errno code is returned. On success the reference counts
- *     are adjusted and the function returns zero.
+ * netdev_has_upper_dev - Check if device is linked to an upper device
+ * @dev: device
+ * @upper_dev: upper device to check
+ *
+ * Find out if a device is linked to specified upper device and return true
+ * in case it is. Note that this checks only immediate upper device,
+ * not through a complete stack of devices. The caller must hold the RTNL lock.
  */
-int netdev_set_master(struct net_device *slave, struct net_device *master)
+bool netdev_has_upper_dev(struct net_device *dev,
+                         struct net_device *upper_dev)
 {
-       struct net_device *old = slave->master;
+       ASSERT_RTNL();
+
+       return __netdev_find_upper(dev, upper_dev);
+}
+EXPORT_SYMBOL(netdev_has_upper_dev);
 
+/**
+ * netdev_has_any_upper_dev - Check if device is linked to some device
+ * @dev: device
+ *
+ * Find out if a device is linked to an upper device and return true in case
+ * it is. The caller must hold the RTNL lock.
+ */
+bool netdev_has_any_upper_dev(struct net_device *dev)
+{
        ASSERT_RTNL();
 
-       if (master) {
-               if (old)
-                       return -EBUSY;
-               dev_hold(master);
-       }
+       return !list_empty(&dev->upper_dev_list);
+}
+EXPORT_SYMBOL(netdev_has_any_upper_dev);
+
+/**
+ * netdev_master_upper_dev_get - Get master upper device
+ * @dev: device
+ *
+ * Find a master upper device and return pointer to it or NULL in case
+ * it's not there. The caller must hold the RTNL lock.
+ */
+struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
+{
+       struct netdev_upper *upper;
 
-       slave->master = master;
+       ASSERT_RTNL();
 
-       if (old)
-               dev_put(old);
-       return 0;
+       if (list_empty(&dev->upper_dev_list))
+               return NULL;
+
+       upper = list_first_entry(&dev->upper_dev_list,
+                                struct netdev_upper, list);
+       if (likely(upper->master))
+               return upper->dev;
+       return NULL;
 }
-EXPORT_SYMBOL(netdev_set_master);
+EXPORT_SYMBOL(netdev_master_upper_dev_get);
 
 /**
- *     netdev_set_bond_master  -       set up bonding master/slave pair
- *     @slave: slave device
- *     @master: new master device
- *
- *     Changes the master device of the slave. Pass %NULL to break the
- *     bonding. The caller must hold the RTNL semaphore. On a failure
- *     a negative errno code is returned. On success %RTM_NEWLINK is sent
- *     to the routing socket and the function returns zero.
+ * netdev_master_upper_dev_get_rcu - Get master upper device
+ * @dev: device
+ *
+ * Find a master upper device and return pointer to it or NULL in case
+ * it's not there. The caller must hold the RCU read lock.
  */
-int netdev_set_bond_master(struct net_device *slave, struct net_device *master)
+struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev)
 {
-       int err;
+       struct netdev_upper *upper;
+
+       upper = list_first_or_null_rcu(&dev->upper_dev_list,
+                                      struct netdev_upper, list);
+       if (upper && likely(upper->master))
+               return upper->dev;
+       return NULL;
+}
+EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu);
+
+static int __netdev_upper_dev_link(struct net_device *dev,
+                                  struct net_device *upper_dev, bool master)
+{
+       struct netdev_upper *upper;
 
        ASSERT_RTNL();
 
-       err = netdev_set_master(slave, master);
-       if (err)
-               return err;
+       if (dev == upper_dev)
+               return -EBUSY;
+
+       /* To prevent loops, check if dev is not upper device to upper_dev. */
+       if (__netdev_search_upper_dev(upper_dev, dev))
+               return -EBUSY;
+
+       if (__netdev_find_upper(dev, upper_dev))
+               return -EEXIST;
+
+       if (master && netdev_master_upper_dev_get(dev))
+               return -EBUSY;
+
+       upper = kmalloc(sizeof(*upper), GFP_KERNEL);
+       if (!upper)
+               return -ENOMEM;
+
+       upper->dev = upper_dev;
+       upper->master = master;
+       INIT_LIST_HEAD(&upper->search_list);
+
+       /* Ensure that master upper link is always the first item in list. */
        if (master)
-               slave->flags |= IFF_SLAVE;
+               list_add_rcu(&upper->list, &dev->upper_dev_list);
        else
-               slave->flags &= ~IFF_SLAVE;
+               list_add_tail_rcu(&upper->list, &dev->upper_dev_list);
+       dev_hold(upper_dev);
 
-       rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE);
        return 0;
 }
-EXPORT_SYMBOL(netdev_set_bond_master);
+
+/**
+ * netdev_upper_dev_link - Add a link to the upper device
+ * @dev: device
+ * @upper_dev: new upper device
+ *
+ * Adds a link to device which is upper to this one. The caller must hold
+ * the RTNL lock. On a failure a negative errno code is returned.
+ * On success the reference counts are adjusted and the function
+ * returns zero.
+ */
+int netdev_upper_dev_link(struct net_device *dev,
+                         struct net_device *upper_dev)
+{
+       return __netdev_upper_dev_link(dev, upper_dev, false);
+}
+EXPORT_SYMBOL(netdev_upper_dev_link);
+
+/**
+ * netdev_master_upper_dev_link - Add a master link to the upper device
+ * @dev: device
+ * @upper_dev: new upper device
+ *
+ * Adds a link to device which is upper to this one. In this case, only
+ * one master upper device can be linked, although other non-master devices
+ * might be linked as well. The caller must hold the RTNL lock.
+ * On a failure a negative errno code is returned. On success the reference
+ * counts are adjusted and the function returns zero.
+ */
+int netdev_master_upper_dev_link(struct net_device *dev,
+                                struct net_device *upper_dev)
+{
+       return __netdev_upper_dev_link(dev, upper_dev, true);
+}
+EXPORT_SYMBOL(netdev_master_upper_dev_link);
+
+/**
+ * netdev_upper_dev_unlink - Removes a link to upper device
+ * @dev: device
+ * @upper_dev: new upper device
+ *
+ * Removes a link to device which is upper to this one. The caller must hold
+ * the RTNL lock.
+ */
+void netdev_upper_dev_unlink(struct net_device *dev,
+                            struct net_device *upper_dev)
+{
+       struct netdev_upper *upper;
+
+       ASSERT_RTNL();
+
+       upper = __netdev_find_upper(dev, upper_dev);
+       if (!upper)
+               return;
+       list_del_rcu(&upper->list);
+       dev_put(upper_dev);
+       kfree_rcu(upper, rcu);
+}
+EXPORT_SYMBOL(netdev_upper_dev_unlink);
 
 static void dev_change_rx_flags(struct net_device *dev, int flags)
 {
@@ -5020,13 +5289,34 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
        if (!netif_device_present(dev))
                return -ENODEV;
        err = ops->ndo_set_mac_address(dev, sa);
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+       if (err)
+               return err;
+       dev->addr_assign_type = NET_ADDR_SET;
+       call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
        add_device_randomness(dev->dev_addr, dev->addr_len);
-       return err;
+       return 0;
 }
 EXPORT_SYMBOL(dev_set_mac_address);
 
+/**
+ *     dev_change_carrier - Change device carrier
+ *     @dev: device
+ *     @new_carries: new value
+ *
+ *     Change device carrier
+ */
+int dev_change_carrier(struct net_device *dev, bool new_carrier)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       if (!ops->ndo_change_carrier)
+               return -EOPNOTSUPP;
+       if (!netif_device_present(dev))
+               return -ENODEV;
+       return ops->ndo_change_carrier(dev, new_carrier);
+}
+EXPORT_SYMBOL(dev_change_carrier);
+
 /*
  *     Perform the SIOCxIFxxx calls, inside rcu_read_lock()
  */
@@ -5482,11 +5772,15 @@ static void rollback_registered_many(struct list_head *head)
                if (dev->netdev_ops->ndo_uninit)
                        dev->netdev_ops->ndo_uninit(dev);
 
-               /* Notifier chain MUST detach us from master device. */
-               WARN_ON(dev->master);
+               /* Notifier chain MUST detach us all upper devices. */
+               WARN_ON(netdev_has_any_upper_dev(dev));
 
                /* Remove entries from kobject tree */
                netdev_unregister_kobject(dev);
+#ifdef CONFIG_XPS
+               /* Remove XPS queueing entries */
+               netif_reset_xps_queues_gt(dev, 0);
+#endif
        }
 
        synchronize_net();
@@ -5815,6 +6109,13 @@ int register_netdevice(struct net_device *dev)
        list_netdevice(dev);
        add_device_randomness(dev->dev_addr, dev->addr_len);
 
+       /* If the device has permanent device address, driver should
+        * set dev_addr and also addr_assign_type should be set to
+        * NET_ADDR_PERM (default value).
+        */
+       if (dev->addr_assign_type == NET_ADDR_PERM)
+               memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
        /* Notify protocols, that a new device appeared. */
        ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
        ret = notifier_to_errno(ret);
@@ -6199,6 +6500,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        INIT_LIST_HEAD(&dev->napi_list);
        INIT_LIST_HEAD(&dev->unreg_list);
        INIT_LIST_HEAD(&dev->link_watch_list);
+       INIT_LIST_HEAD(&dev->upper_dev_list);
        dev->priv_flags = IFF_XMIT_DST_RELEASE;
        setup(dev);
 
@@ -6849,12 +7151,3 @@ out:
 }
 
 subsys_initcall(net_dev_init);
-
-static int __init initialize_hashrnd(void)
-{
-       get_random_bytes(&hashrnd, sizeof(hashrnd));
-       return 0;
-}
-
-late_initcall_sync(initialize_hashrnd);
-
index a8705432e4b1923073b5ed3565daa3baa9d39fa7..d9d55209db679ba4e0e16789a9a988e147fd1022 100644 (file)
@@ -175,7 +175,7 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset)
        if (sset == ETH_SS_FEATURES)
                return ARRAY_SIZE(netdev_features_strings);
 
-       if (ops && ops->get_sset_count && ops->get_strings)
+       if (ops->get_sset_count && ops->get_strings)
                return ops->get_sset_count(dev, sset);
        else
                return -EOPNOTSUPP;
@@ -311,7 +311,7 @@ int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        ASSERT_RTNL();
 
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
+       if (!dev->ethtool_ops->get_settings)
                return -EOPNOTSUPP;
 
        memset(cmd, 0, sizeof(struct ethtool_cmd));
@@ -355,7 +355,7 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
 
        memset(&info, 0, sizeof(info));
        info.cmd = ETHTOOL_GDRVINFO;
-       if (ops && ops->get_drvinfo) {
+       if (ops->get_drvinfo) {
                ops->get_drvinfo(dev, &info);
        } else if (dev->dev.parent && dev->dev.parent->driver) {
                strlcpy(info.bus_info, dev_name(dev->dev.parent),
@@ -370,7 +370,7 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
         * this method of obtaining string set info is deprecated;
         * Use ETHTOOL_GSSET_INFO instead.
         */
-       if (ops && ops->get_sset_count) {
+       if (ops->get_sset_count) {
                int rc;
 
                rc = ops->get_sset_count(dev, ETH_SS_TEST);
@@ -383,9 +383,9 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
                if (rc >= 0)
                        info.n_priv_flags = rc;
        }
-       if (ops && ops->get_regs_len)
+       if (ops->get_regs_len)
                info.regdump_len = ops->get_regs_len(dev);
-       if (ops && ops->get_eeprom_len)
+       if (ops->get_eeprom_len)
                info.eedump_len = ops->get_eeprom_len(dev);
 
        if (copy_to_user(useraddr, &info, sizeof(info)))
@@ -590,13 +590,14 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
        struct ethtool_rxnfc rx_rings;
        u32 user_size, dev_size, i;
        u32 *indir;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
        int ret;
 
-       if (!dev->ethtool_ops->get_rxfh_indir_size ||
-           !dev->ethtool_ops->set_rxfh_indir ||
-           !dev->ethtool_ops->get_rxnfc)
+       if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir ||
+           !ops->get_rxnfc)
                return -EOPNOTSUPP;
-       dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
+
+       dev_size = ops->get_rxfh_indir_size(dev);
        if (dev_size == 0)
                return -EOPNOTSUPP;
 
@@ -613,7 +614,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
                return -ENOMEM;
 
        rx_rings.cmd = ETHTOOL_GRXRINGS;
-       ret = dev->ethtool_ops->get_rxnfc(dev, &rx_rings, NULL);
+       ret = ops->get_rxnfc(dev, &rx_rings, NULL);
        if (ret)
                goto out;
 
@@ -639,7 +640,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
                }
        }
 
-       ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);
+       ret = ops->set_rxfh_indir(dev, indir);
 
 out:
        kfree(indir);
@@ -1082,9 +1083,10 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_value id;
        static bool busy;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
        int rc;
 
-       if (!dev->ethtool_ops->set_phys_id)
+       if (!ops->set_phys_id)
                return -EOPNOTSUPP;
 
        if (busy)
@@ -1093,7 +1095,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
        if (copy_from_user(&id, useraddr, sizeof(id)))
                return -EFAULT;
 
-       rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
+       rc = ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
        if (rc < 0)
                return rc;
 
@@ -1118,7 +1120,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
                        i = n;
                        do {
                                rtnl_lock();
-                               rc = dev->ethtool_ops->set_phys_id(dev,
+                               rc = ops->set_phys_id(dev,
                                    (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
                                rtnl_unlock();
                                if (rc)
@@ -1133,7 +1135,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
        dev_put(dev);
        busy = false;
 
-       (void)dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
+       (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
        return rc;
 }
 
@@ -1275,7 +1277,7 @@ static int ethtool_get_dump_flag(struct net_device *dev,
        struct ethtool_dump dump;
        const struct ethtool_ops *ops = dev->ethtool_ops;
 
-       if (!dev->ethtool_ops->get_dump_flag)
+       if (!ops->get_dump_flag)
                return -EOPNOTSUPP;
 
        if (copy_from_user(&dump, useraddr, sizeof(dump)))
@@ -1299,8 +1301,7 @@ static int ethtool_get_dump_data(struct net_device *dev,
        const struct ethtool_ops *ops = dev->ethtool_ops;
        void *data = NULL;
 
-       if (!dev->ethtool_ops->get_dump_data ||
-               !dev->ethtool_ops->get_dump_flag)
+       if (!ops->get_dump_data || !ops->get_dump_flag)
                return -EOPNOTSUPP;
 
        if (copy_from_user(&dump, useraddr, sizeof(dump)))
@@ -1346,13 +1347,9 @@ static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
        info.cmd = ETHTOOL_GET_TS_INFO;
 
        if (phydev && phydev->drv && phydev->drv->ts_info) {
-
                err = phydev->drv->ts_info(phydev, &info);
-
-       } else if (dev->ethtool_ops && dev->ethtool_ops->get_ts_info) {
-
+       } else if (ops->get_ts_info) {
                err = ops->get_ts_info(dev, &info);
-
        } else {
                info.so_timestamping =
                        SOF_TIMESTAMPING_RX_SOFTWARE |
index c23543cba132bc19a213ed242e47386e8e41ca65..2e20b55a7830c43e25bdd4221cc134f374d7148e 100644 (file)
@@ -532,6 +532,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
                [BPF_JMP|BPF_JSET|BPF_X] = BPF_S_JMP_JSET_X,
        };
        int pc;
+       bool anc_found;
 
        if (flen == 0 || flen > BPF_MAXINSNS)
                return -EINVAL;
@@ -592,8 +593,10 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
                case BPF_S_LD_W_ABS:
                case BPF_S_LD_H_ABS:
                case BPF_S_LD_B_ABS:
+                       anc_found = false;
 #define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE:       \
                                code = BPF_S_ANC_##CODE;        \
+                               anc_found = true;               \
                                break
                        switch (ftest->k) {
                        ANCILLARY(PROTOCOL);
@@ -610,6 +613,10 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
                        ANCILLARY(VLAN_TAG);
                        ANCILLARY(VLAN_TAG_PRESENT);
                        }
+
+                       /* ancillary operation unknown or unsupported */
+                       if (anc_found == false && ftest->k >= SKF_AD_OFF)
+                               return -EINVAL;
                }
                ftest->code = code;
        }
@@ -714,6 +721,9 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
        int err;
 
+       if (sock_flag(sk, SOCK_FILTER_LOCKED))
+               return -EPERM;
+
        /* Make sure new filter is there and in the right amounts. */
        if (fprog->filter == NULL)
                return -EINVAL;
@@ -750,6 +760,9 @@ int sk_detach_filter(struct sock *sk)
        int ret = -ENOENT;
        struct sk_filter *filter;
 
+       if (sock_flag(sk, SOCK_FILTER_LOCKED))
+               return -EPERM;
+
        filter = rcu_dereference_protected(sk->sk_filter,
                                           sock_owned_by_user(sk));
        if (filter) {
index b0901ee5a0025f93e32287c1acbb3ef0ded0f47a..43f7495df27a932659c714fbf7b897ab6eca2716 100644 (file)
@@ -286,7 +286,7 @@ nocache:
                else
                        fle->genid--;
        } else {
-               if (flo && !IS_ERR(flo))
+               if (!IS_ERR_OR_NULL(flo))
                        flo->ops->delete(flo);
        }
 ret_object:
index 466820b6e34400787a18fb0be5f26845c2fc0629..9d4c7201400d154ab2fd00ccfab4f22f8bddb5ff 100644 (file)
@@ -143,3 +143,176 @@ ipv6:
        return true;
 }
 EXPORT_SYMBOL(skb_flow_dissect);
+
+static u32 hashrnd __read_mostly;
+
+/*
+ * __skb_get_rxhash: calculate a flow hash based on src/dst addresses
+ * and src/dst port numbers.  Sets rxhash in skb to non-zero hash value
+ * on success, zero indicates no valid hash.  Also, sets l4_rxhash in skb
+ * if hash is a canonical 4-tuple hash over transport ports.
+ */
+void __skb_get_rxhash(struct sk_buff *skb)
+{
+       struct flow_keys keys;
+       u32 hash;
+
+       if (!skb_flow_dissect(skb, &keys))
+               return;
+
+       if (keys.ports)
+               skb->l4_rxhash = 1;
+
+       /* get a consistent hash (same value on both flow directions) */
+       if (((__force u32)keys.dst < (__force u32)keys.src) ||
+           (((__force u32)keys.dst == (__force u32)keys.src) &&
+            ((__force u16)keys.port16[1] < (__force u16)keys.port16[0]))) {
+               swap(keys.dst, keys.src);
+               swap(keys.port16[0], keys.port16[1]);
+       }
+
+       hash = jhash_3words((__force u32)keys.dst,
+                           (__force u32)keys.src,
+                           (__force u32)keys.ports, hashrnd);
+       if (!hash)
+               hash = 1;
+
+       skb->rxhash = hash;
+}
+EXPORT_SYMBOL(__skb_get_rxhash);
+
+/*
+ * Returns a Tx hash based on the given packet descriptor a Tx queues' number
+ * to be used as a distribution range.
+ */
+u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb,
+                 unsigned int num_tx_queues)
+{
+       u32 hash;
+       u16 qoffset = 0;
+       u16 qcount = num_tx_queues;
+
+       if (skb_rx_queue_recorded(skb)) {
+               hash = skb_get_rx_queue(skb);
+               while (unlikely(hash >= num_tx_queues))
+                       hash -= num_tx_queues;
+               return hash;
+       }
+
+       if (dev->num_tc) {
+               u8 tc = netdev_get_prio_tc_map(dev, skb->priority);
+               qoffset = dev->tc_to_txq[tc].offset;
+               qcount = dev->tc_to_txq[tc].count;
+       }
+
+       if (skb->sk && skb->sk->sk_hash)
+               hash = skb->sk->sk_hash;
+       else
+               hash = (__force u16) skb->protocol;
+       hash = jhash_1word(hash, hashrnd);
+
+       return (u16) (((u64) hash * qcount) >> 32) + qoffset;
+}
+EXPORT_SYMBOL(__skb_tx_hash);
+
+static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
+{
+       if (unlikely(queue_index >= dev->real_num_tx_queues)) {
+               net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n",
+                                    dev->name, queue_index,
+                                    dev->real_num_tx_queues);
+               return 0;
+       }
+       return queue_index;
+}
+
+static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
+{
+#ifdef CONFIG_XPS
+       struct xps_dev_maps *dev_maps;
+       struct xps_map *map;
+       int queue_index = -1;
+
+       rcu_read_lock();
+       dev_maps = rcu_dereference(dev->xps_maps);
+       if (dev_maps) {
+               map = rcu_dereference(
+                   dev_maps->cpu_map[raw_smp_processor_id()]);
+               if (map) {
+                       if (map->len == 1)
+                               queue_index = map->queues[0];
+                       else {
+                               u32 hash;
+                               if (skb->sk && skb->sk->sk_hash)
+                                       hash = skb->sk->sk_hash;
+                               else
+                                       hash = (__force u16) skb->protocol ^
+                                           skb->rxhash;
+                               hash = jhash_1word(hash, hashrnd);
+                               queue_index = map->queues[
+                                   ((u64)hash * map->len) >> 32];
+                       }
+                       if (unlikely(queue_index >= dev->real_num_tx_queues))
+                               queue_index = -1;
+               }
+       }
+       rcu_read_unlock();
+
+       return queue_index;
+#else
+       return -1;
+#endif
+}
+
+u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       int queue_index = sk_tx_queue_get(sk);
+
+       if (queue_index < 0 || skb->ooo_okay ||
+           queue_index >= dev->real_num_tx_queues) {
+               int new_index = get_xps_queue(dev, skb);
+               if (new_index < 0)
+                       new_index = skb_tx_hash(dev, skb);
+
+               if (queue_index != new_index && sk) {
+                       struct dst_entry *dst =
+                                   rcu_dereference_check(sk->sk_dst_cache, 1);
+
+                       if (dst && skb_dst(skb) == dst)
+                               sk_tx_queue_set(sk, queue_index);
+
+               }
+
+               queue_index = new_index;
+       }
+
+       return queue_index;
+}
+EXPORT_SYMBOL(__netdev_pick_tx);
+
+struct netdev_queue *netdev_pick_tx(struct net_device *dev,
+                                   struct sk_buff *skb)
+{
+       int queue_index = 0;
+
+       if (dev->real_num_tx_queues != 1) {
+               const struct net_device_ops *ops = dev->netdev_ops;
+               if (ops->ndo_select_queue)
+                       queue_index = ops->ndo_select_queue(dev, skb);
+               else
+                       queue_index = __netdev_pick_tx(dev, skb);
+               queue_index = dev_cap_txqueue(dev, queue_index);
+       }
+
+       skb_set_queue_mapping(skb, queue_index);
+       return netdev_get_tx_queue(dev, queue_index);
+}
+
+static int __init initialize_hashrnd(void)
+{
+       get_random_bytes(&hashrnd, sizeof(hashrnd));
+       return 0;
+}
+
+late_initcall_sync(initialize_hashrnd);
index c815f285e5ab76e354dd7752f7ef1c1049154570..3863b8f639c50827dfdf4a0c6c26bd6284f39f58 100644 (file)
@@ -290,15 +290,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device
                        goto out_entries;
        }
 
-       if (tbl->entry_size)
-               n = kzalloc(tbl->entry_size, GFP_ATOMIC);
-       else {
-               int sz = sizeof(*n) + tbl->key_len;
-
-               sz = ALIGN(sz, NEIGH_PRIV_ALIGN);
-               sz += dev->neigh_priv_len;
-               n = kzalloc(sz, GFP_ATOMIC);
-       }
+       n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
        if (!n)
                goto out_entries;
 
@@ -778,6 +770,9 @@ static void neigh_periodic_work(struct work_struct *work)
        nht = rcu_dereference_protected(tbl->nht,
                                        lockdep_is_held(&tbl->lock));
 
+       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
+               goto out;
+
        /*
         *      periodically recompute ReachableTime from random function
         */
@@ -832,6 +827,7 @@ next_elt:
                nht = rcu_dereference_protected(tbl->nht,
                                                lockdep_is_held(&tbl->lock));
        }
+out:
        /* Cycle through all hash buckets every base_reachable_time/2 ticks.
         * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
         * base_reachable_time.
@@ -1542,6 +1538,12 @@ static void neigh_table_init_no_netlink(struct neigh_table *tbl)
        if (!tbl->nht || !tbl->phash_buckets)
                panic("cannot allocate neighbour cache hashes");
 
+       if (!tbl->entry_size)
+               tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
+                                       tbl->key_len, NEIGH_PRIV_ALIGN);
+       else
+               WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
+
        rwlock_init(&tbl->lock);
        INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
        schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
index 28c5f5aa7ca7e019b93e07f4d58a6758a7f5a78b..a5b89a6fec6d990bd49caf4fa258fc916a11ed14 100644 (file)
@@ -126,6 +126,19 @@ static ssize_t show_broadcast(struct device *dev,
        return -EINVAL;
 }
 
+static int change_carrier(struct net_device *net, unsigned long new_carrier)
+{
+       if (!netif_running(net))
+               return -EINVAL;
+       return dev_change_carrier(net, (bool) new_carrier);
+}
+
+static ssize_t store_carrier(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t len)
+{
+       return netdev_store(dev, attr, buf, len, change_carrier);
+}
+
 static ssize_t show_carrier(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
@@ -331,7 +344,7 @@ static struct device_attribute net_class_attributes[] = {
        __ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
        __ATTR(address, S_IRUGO, show_address, NULL),
        __ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
-       __ATTR(carrier, S_IRUGO, show_carrier, NULL),
+       __ATTR(carrier, S_IRUGO | S_IWUSR, show_carrier, store_carrier),
        __ATTR(speed, S_IRUGO, show_speed, NULL),
        __ATTR(duplex, S_IRUGO, show_duplex, NULL),
        __ATTR(dormant, S_IRUGO, show_dormant, NULL),
@@ -989,68 +1002,14 @@ static ssize_t show_xps_map(struct netdev_queue *queue,
        return len;
 }
 
-static DEFINE_MUTEX(xps_map_mutex);
-#define xmap_dereference(P)            \
-       rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex))
-
-static void xps_queue_release(struct netdev_queue *queue)
-{
-       struct net_device *dev = queue->dev;
-       struct xps_dev_maps *dev_maps;
-       struct xps_map *map;
-       unsigned long index;
-       int i, pos, nonempty = 0;
-
-       index = get_netdev_queue_index(queue);
-
-       mutex_lock(&xps_map_mutex);
-       dev_maps = xmap_dereference(dev->xps_maps);
-
-       if (dev_maps) {
-               for_each_possible_cpu(i) {
-                       map = xmap_dereference(dev_maps->cpu_map[i]);
-                       if (!map)
-                               continue;
-
-                       for (pos = 0; pos < map->len; pos++)
-                               if (map->queues[pos] == index)
-                                       break;
-
-                       if (pos < map->len) {
-                               if (map->len > 1)
-                                       map->queues[pos] =
-                                           map->queues[--map->len];
-                               else {
-                                       RCU_INIT_POINTER(dev_maps->cpu_map[i],
-                                           NULL);
-                                       kfree_rcu(map, rcu);
-                                       map = NULL;
-                               }
-                       }
-                       if (map)
-                               nonempty = 1;
-               }
-
-               if (!nonempty) {
-                       RCU_INIT_POINTER(dev->xps_maps, NULL);
-                       kfree_rcu(dev_maps, rcu);
-               }
-       }
-       mutex_unlock(&xps_map_mutex);
-}
-
 static ssize_t store_xps_map(struct netdev_queue *queue,
                      struct netdev_queue_attribute *attribute,
                      const char *buf, size_t len)
 {
        struct net_device *dev = queue->dev;
-       cpumask_var_t mask;
-       int err, i, cpu, pos, map_len, alloc_len, need_set;
        unsigned long index;
-       struct xps_map *map, *new_map;
-       struct xps_dev_maps *dev_maps, *new_dev_maps;
-       int nonempty = 0;
-       int numa_node_id = -2;
+       cpumask_var_t mask;
+       int err;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -1066,105 +1025,11 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
                return err;
        }
 
-       new_dev_maps = kzalloc(max_t(unsigned int,
-           XPS_DEV_MAPS_SIZE, L1_CACHE_BYTES), GFP_KERNEL);
-       if (!new_dev_maps) {
-               free_cpumask_var(mask);
-               return -ENOMEM;
-       }
-
-       mutex_lock(&xps_map_mutex);
-
-       dev_maps = xmap_dereference(dev->xps_maps);
-
-       for_each_possible_cpu(cpu) {
-               map = dev_maps ?
-                       xmap_dereference(dev_maps->cpu_map[cpu]) : NULL;
-               new_map = map;
-               if (map) {
-                       for (pos = 0; pos < map->len; pos++)
-                               if (map->queues[pos] == index)
-                                       break;
-                       map_len = map->len;
-                       alloc_len = map->alloc_len;
-               } else
-                       pos = map_len = alloc_len = 0;
-
-               need_set = cpumask_test_cpu(cpu, mask) && cpu_online(cpu);
-#ifdef CONFIG_NUMA
-               if (need_set) {
-                       if (numa_node_id == -2)
-                               numa_node_id = cpu_to_node(cpu);
-                       else if (numa_node_id != cpu_to_node(cpu))
-                               numa_node_id = -1;
-               }
-#endif
-               if (need_set && pos >= map_len) {
-                       /* Need to add queue to this CPU's map */
-                       if (map_len >= alloc_len) {
-                               alloc_len = alloc_len ?
-                                   2 * alloc_len : XPS_MIN_MAP_ALLOC;
-                               new_map = kzalloc_node(XPS_MAP_SIZE(alloc_len),
-                                                      GFP_KERNEL,
-                                                      cpu_to_node(cpu));
-                               if (!new_map)
-                                       goto error;
-                               new_map->alloc_len = alloc_len;
-                               for (i = 0; i < map_len; i++)
-                                       new_map->queues[i] = map->queues[i];
-                               new_map->len = map_len;
-                       }
-                       new_map->queues[new_map->len++] = index;
-               } else if (!need_set && pos < map_len) {
-                       /* Need to remove queue from this CPU's map */
-                       if (map_len > 1)
-                               new_map->queues[pos] =
-                                   new_map->queues[--new_map->len];
-                       else
-                               new_map = NULL;
-               }
-               RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], new_map);
-       }
-
-       /* Cleanup old maps */
-       for_each_possible_cpu(cpu) {
-               map = dev_maps ?
-                       xmap_dereference(dev_maps->cpu_map[cpu]) : NULL;
-               if (map && xmap_dereference(new_dev_maps->cpu_map[cpu]) != map)
-                       kfree_rcu(map, rcu);
-               if (new_dev_maps->cpu_map[cpu])
-                       nonempty = 1;
-       }
-
-       if (nonempty) {
-               rcu_assign_pointer(dev->xps_maps, new_dev_maps);
-       } else {
-               kfree(new_dev_maps);
-               RCU_INIT_POINTER(dev->xps_maps, NULL);
-       }
-
-       if (dev_maps)
-               kfree_rcu(dev_maps, rcu);
-
-       netdev_queue_numa_node_write(queue, (numa_node_id >= 0) ? numa_node_id :
-                                           NUMA_NO_NODE);
-
-       mutex_unlock(&xps_map_mutex);
+       err = netif_set_xps_queue(dev, mask, index);
 
        free_cpumask_var(mask);
-       return len;
 
-error:
-       mutex_unlock(&xps_map_mutex);
-
-       if (new_dev_maps)
-               for_each_possible_cpu(i)
-                       kfree(rcu_dereference_protected(
-                               new_dev_maps->cpu_map[i],
-                               1));
-       kfree(new_dev_maps);
-       free_cpumask_var(mask);
-       return -ENOMEM;
+       return err ? : len;
 }
 
 static struct netdev_queue_attribute xps_cpus_attribute =
@@ -1183,10 +1048,6 @@ static void netdev_queue_release(struct kobject *kobj)
 {
        struct netdev_queue *queue = to_netdev_queue(kobj);
 
-#ifdef CONFIG_XPS
-       xps_queue_release(queue);
-#endif
-
        memset(kobj, 0, sizeof(*kobj));
        dev_put(queue->dev);
 }
index 3151acf5ec13afb34480a28a3f4a73deae69990a..331ccb90f9157e1c6aac6db1af4cc9ded362b1a2 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/if_vlan.h>
 #include <net/tcp.h>
 #include <net/udp.h>
+#include <net/addrconf.h>
+#include <net/ndisc.h>
+#include <net/ip6_checksum.h>
 #include <asm/unaligned.h>
 #include <trace/events/napi.h>
 
@@ -55,7 +58,7 @@ static atomic_t trapped;
         MAX_UDP_CHUNK)
 
 static void zap_completion_queue(void);
-static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
+static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
 
 static unsigned int carrier_timeout = 4;
 module_param(carrier_timeout, uint, 0644);
@@ -181,13 +184,13 @@ static void poll_napi(struct net_device *dev)
        }
 }
 
-static void service_arp_queue(struct netpoll_info *npi)
+static void service_neigh_queue(struct netpoll_info *npi)
 {
        if (npi) {
                struct sk_buff *skb;
 
-               while ((skb = skb_dequeue(&npi->arp_tx)))
-                       netpoll_arp_reply(skb, npi);
+               while ((skb = skb_dequeue(&npi->neigh_tx)))
+                       netpoll_neigh_reply(skb, npi);
        }
 }
 
@@ -210,17 +213,20 @@ static void netpoll_poll_dev(struct net_device *dev)
 
        if (dev->flags & IFF_SLAVE) {
                if (ni) {
-                       struct net_device *bond_dev = dev->master;
+                       struct net_device *bond_dev;
                        struct sk_buff *skb;
-                       struct netpoll_info *bond_ni = rcu_dereference_bh(bond_dev->npinfo);
-                       while ((skb = skb_dequeue(&ni->arp_tx))) {
+                       struct netpoll_info *bond_ni;
+
+                       bond_dev = netdev_master_upper_dev_get_rcu(dev);
+                       bond_ni = rcu_dereference_bh(bond_dev->npinfo);
+                       while ((skb = skb_dequeue(&ni->neigh_tx))) {
                                skb->dev = bond_dev;
-                               skb_queue_tail(&bond_ni->arp_tx, skb);
+                               skb_queue_tail(&bond_ni->neigh_tx, skb);
                        }
                }
        }
 
-       service_arp_queue(ni);
+       service_neigh_queue(ni);
 
        zap_completion_queue();
 }
@@ -381,9 +387,14 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
        struct iphdr *iph;
        struct ethhdr *eth;
        static atomic_t ip_ident;
+       struct ipv6hdr *ip6h;
 
        udp_len = len + sizeof(*udph);
-       ip_len = udp_len + sizeof(*iph);
+       if (np->ipv6)
+               ip_len = udp_len + sizeof(*ip6h);
+       else
+               ip_len = udp_len + sizeof(*iph);
+
        total_len = ip_len + LL_RESERVED_SPACE(np->dev);
 
        skb = find_skb(np, total_len + np->dev->needed_tailroom,
@@ -400,34 +411,66 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
        udph->source = htons(np->local_port);
        udph->dest = htons(np->remote_port);
        udph->len = htons(udp_len);
-       udph->check = 0;
-       udph->check = csum_tcpudp_magic(np->local_ip,
-                                       np->remote_ip,
-                                       udp_len, IPPROTO_UDP,
-                                       csum_partial(udph, udp_len, 0));
-       if (udph->check == 0)
-               udph->check = CSUM_MANGLED_0;
-
-       skb_push(skb, sizeof(*iph));
-       skb_reset_network_header(skb);
-       iph = ip_hdr(skb);
-
-       /* iph->version = 4; iph->ihl = 5; */
-       put_unaligned(0x45, (unsigned char *)iph);
-       iph->tos      = 0;
-       put_unaligned(htons(ip_len), &(iph->tot_len));
-       iph->id       = htons(atomic_inc_return(&ip_ident));
-       iph->frag_off = 0;
-       iph->ttl      = 64;
-       iph->protocol = IPPROTO_UDP;
-       iph->check    = 0;
-       put_unaligned(np->local_ip, &(iph->saddr));
-       put_unaligned(np->remote_ip, &(iph->daddr));
-       iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
-       eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-       skb_reset_mac_header(skb);
-       skb->protocol = eth->h_proto = htons(ETH_P_IP);
+
+       if (np->ipv6) {
+               udph->check = 0;
+               udph->check = csum_ipv6_magic(&np->local_ip.in6,
+                                             &np->remote_ip.in6,
+                                             udp_len, IPPROTO_UDP,
+                                             csum_partial(udph, udp_len, 0));
+               if (udph->check == 0)
+                       udph->check = CSUM_MANGLED_0;
+
+               skb_push(skb, sizeof(*ip6h));
+               skb_reset_network_header(skb);
+               ip6h = ipv6_hdr(skb);
+
+               /* ip6h->version = 6; ip6h->priority = 0; */
+               put_unaligned(0x60, (unsigned char *)ip6h);
+               ip6h->flow_lbl[0] = 0;
+               ip6h->flow_lbl[1] = 0;
+               ip6h->flow_lbl[2] = 0;
+
+               ip6h->payload_len = htons(sizeof(struct udphdr) + len);
+               ip6h->nexthdr = IPPROTO_UDP;
+               ip6h->hop_limit = 32;
+               ip6h->saddr = np->local_ip.in6;
+               ip6h->daddr = np->remote_ip.in6;
+
+               eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+               skb_reset_mac_header(skb);
+               skb->protocol = eth->h_proto = htons(ETH_P_IPV6);
+       } else {
+               udph->check = 0;
+               udph->check = csum_tcpudp_magic(np->local_ip.ip,
+                                               np->remote_ip.ip,
+                                               udp_len, IPPROTO_UDP,
+                                               csum_partial(udph, udp_len, 0));
+               if (udph->check == 0)
+                       udph->check = CSUM_MANGLED_0;
+
+               skb_push(skb, sizeof(*iph));
+               skb_reset_network_header(skb);
+               iph = ip_hdr(skb);
+
+               /* iph->version = 4; iph->ihl = 5; */
+               put_unaligned(0x45, (unsigned char *)iph);
+               iph->tos      = 0;
+               put_unaligned(htons(ip_len), &(iph->tot_len));
+               iph->id       = htons(atomic_inc_return(&ip_ident));
+               iph->frag_off = 0;
+               iph->ttl      = 64;
+               iph->protocol = IPPROTO_UDP;
+               iph->check    = 0;
+               put_unaligned(np->local_ip.ip, &(iph->saddr));
+               put_unaligned(np->remote_ip.ip, &(iph->daddr));
+               iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+               eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+               skb_reset_mac_header(skb);
+               skb->protocol = eth->h_proto = htons(ETH_P_IP);
+       }
+
        memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN);
        memcpy(eth->h_dest, np->remote_mac, ETH_ALEN);
 
@@ -437,18 +480,16 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 }
 EXPORT_SYMBOL(netpoll_send_udp);
 
-static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
+static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
-       struct arphdr *arp;
-       unsigned char *arp_ptr;
-       int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
+       int size, type = ARPOP_REPLY;
        __be32 sip, tip;
        unsigned char *sha;
        struct sk_buff *send_skb;
        struct netpoll *np, *tmp;
        unsigned long flags;
        int hlen, tlen;
-       int hits = 0;
+       int hits = 0, proto;
 
        if (list_empty(&npinfo->rx_np))
                return;
@@ -466,94 +507,214 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
        if (!hits)
                return;
 
-       /* No arp on this interface */
-       if (skb->dev->flags & IFF_NOARP)
-               return;
-
-       if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
-               return;
+       proto = ntohs(eth_hdr(skb)->h_proto);
+       if (proto == ETH_P_IP) {
+               struct arphdr *arp;
+               unsigned char *arp_ptr;
+               /* No arp on this interface */
+               if (skb->dev->flags & IFF_NOARP)
+                       return;
 
-       skb_reset_network_header(skb);
-       skb_reset_transport_header(skb);
-       arp = arp_hdr(skb);
+               if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
+                       return;
 
-       if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
-            arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
-           arp->ar_pro != htons(ETH_P_IP) ||
-           arp->ar_op != htons(ARPOP_REQUEST))
-               return;
+               skb_reset_network_header(skb);
+               skb_reset_transport_header(skb);
+               arp = arp_hdr(skb);
 
-       arp_ptr = (unsigned char *)(arp+1);
-       /* save the location of the src hw addr */
-       sha = arp_ptr;
-       arp_ptr += skb->dev->addr_len;
-       memcpy(&sip, arp_ptr, 4);
-       arp_ptr += 4;
-       /* If we actually cared about dst hw addr,
-          it would get copied here */
-       arp_ptr += skb->dev->addr_len;
-       memcpy(&tip, arp_ptr, 4);
-
-       /* Should we ignore arp? */
-       if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
-               return;
+               if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
+                    arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
+                   arp->ar_pro != htons(ETH_P_IP) ||
+                   arp->ar_op != htons(ARPOP_REQUEST))
+                       return;
 
-       size = arp_hdr_len(skb->dev);
+               arp_ptr = (unsigned char *)(arp+1);
+               /* save the location of the src hw addr */
+               sha = arp_ptr;
+               arp_ptr += skb->dev->addr_len;
+               memcpy(&sip, arp_ptr, 4);
+               arp_ptr += 4;
+               /* If we actually cared about dst hw addr,
+                  it would get copied here */
+               arp_ptr += skb->dev->addr_len;
+               memcpy(&tip, arp_ptr, 4);
 
-       spin_lock_irqsave(&npinfo->rx_lock, flags);
-       list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-               if (tip != np->local_ip)
-                       continue;
+               /* Should we ignore arp? */
+               if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
+                       return;
 
-               hlen = LL_RESERVED_SPACE(np->dev);
-               tlen = np->dev->needed_tailroom;
-               send_skb = find_skb(np, size + hlen + tlen, hlen);
-               if (!send_skb)
-                       continue;
+               size = arp_hdr_len(skb->dev);
 
-               skb_reset_network_header(send_skb);
-               arp = (struct arphdr *) skb_put(send_skb, size);
-               send_skb->dev = skb->dev;
-               send_skb->protocol = htons(ETH_P_ARP);
+               spin_lock_irqsave(&npinfo->rx_lock, flags);
+               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+                       if (tip != np->local_ip.ip)
+                               continue;
+
+                       hlen = LL_RESERVED_SPACE(np->dev);
+                       tlen = np->dev->needed_tailroom;
+                       send_skb = find_skb(np, size + hlen + tlen, hlen);
+                       if (!send_skb)
+                               continue;
+
+                       skb_reset_network_header(send_skb);
+                       arp = (struct arphdr *) skb_put(send_skb, size);
+                       send_skb->dev = skb->dev;
+                       send_skb->protocol = htons(ETH_P_ARP);
+
+                       /* Fill the device header for the ARP frame */
+                       if (dev_hard_header(send_skb, skb->dev, ETH_P_ARP,
+                                           sha, np->dev->dev_addr,
+                                           send_skb->len) < 0) {
+                               kfree_skb(send_skb);
+                               continue;
+                       }
 
-               /* Fill the device header for the ARP frame */
-               if (dev_hard_header(send_skb, skb->dev, ptype,
-                                   sha, np->dev->dev_addr,
-                                   send_skb->len) < 0) {
-                       kfree_skb(send_skb);
-                       continue;
+                       /*
+                        * Fill out the arp protocol part.
+                        *
+                        * we only support ethernet device type,
+                        * which (according to RFC 1390) should
+                        * always equal 1 (Ethernet).
+                        */
+
+                       arp->ar_hrd = htons(np->dev->type);
+                       arp->ar_pro = htons(ETH_P_IP);
+                       arp->ar_hln = np->dev->addr_len;
+                       arp->ar_pln = 4;
+                       arp->ar_op = htons(type);
+
+                       arp_ptr = (unsigned char *)(arp + 1);
+                       memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
+                       arp_ptr += np->dev->addr_len;
+                       memcpy(arp_ptr, &tip, 4);
+                       arp_ptr += 4;
+                       memcpy(arp_ptr, sha, np->dev->addr_len);
+                       arp_ptr += np->dev->addr_len;
+                       memcpy(arp_ptr, &sip, 4);
+
+                       netpoll_send_skb(np, send_skb);
+
+                       /* If there are several rx_hooks for the same address,
+                          we're fine by sending a single reply */
+                       break;
                }
+               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+       } else if( proto == ETH_P_IPV6) {
+#if IS_ENABLED(CONFIG_IPV6)
+               struct nd_msg *msg;
+               u8 *lladdr = NULL;
+               struct ipv6hdr *hdr;
+               struct icmp6hdr *icmp6h;
+               const struct in6_addr *saddr;
+               const struct in6_addr *daddr;
+               struct inet6_dev *in6_dev = NULL;
+               struct in6_addr *target;
+
+               in6_dev = in6_dev_get(skb->dev);
+               if (!in6_dev || !in6_dev->cnf.accept_ra)
+                       return;
 
-               /*
-                * Fill out the arp protocol part.
-                *
-                * we only support ethernet device type,
-                * which (according to RFC 1390) should
-                * always equal 1 (Ethernet).
-                */
+               if (!pskb_may_pull(skb, skb->len))
+                       return;
 
-               arp->ar_hrd = htons(np->dev->type);
-               arp->ar_pro = htons(ETH_P_IP);
-               arp->ar_hln = np->dev->addr_len;
-               arp->ar_pln = 4;
-               arp->ar_op = htons(type);
+               msg = (struct nd_msg *)skb_transport_header(skb);
 
-               arp_ptr = (unsigned char *)(arp + 1);
-               memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
-               arp_ptr += np->dev->addr_len;
-               memcpy(arp_ptr, &tip, 4);
-               arp_ptr += 4;
-               memcpy(arp_ptr, sha, np->dev->addr_len);
-               arp_ptr += np->dev->addr_len;
-               memcpy(arp_ptr, &sip, 4);
+               __skb_push(skb, skb->data - skb_transport_header(skb));
+
+               if (ipv6_hdr(skb)->hop_limit != 255)
+                       return;
+               if (msg->icmph.icmp6_code != 0)
+                       return;
+               if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
+                       return;
+
+               saddr = &ipv6_hdr(skb)->saddr;
+               daddr = &ipv6_hdr(skb)->daddr;
 
-               netpoll_send_skb(np, send_skb);
+               size = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 
-               /* If there are several rx_hooks for the same address,
-                  we're fine by sending a single reply */
-               break;
+               spin_lock_irqsave(&npinfo->rx_lock, flags);
+               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+                       if (!ipv6_addr_equal(daddr, &np->local_ip.in6))
+                               continue;
+
+                       hlen = LL_RESERVED_SPACE(np->dev);
+                       tlen = np->dev->needed_tailroom;
+                       send_skb = find_skb(np, size + hlen + tlen, hlen);
+                       if (!send_skb)
+                               continue;
+
+                       send_skb->protocol = htons(ETH_P_IPV6);
+                       send_skb->dev = skb->dev;
+
+                       skb_reset_network_header(send_skb);
+                       skb_put(send_skb, sizeof(struct ipv6hdr));
+                       hdr = ipv6_hdr(send_skb);
+
+                       *(__be32*)hdr = htonl(0x60000000);
+
+                       hdr->payload_len = htons(size);
+                       hdr->nexthdr = IPPROTO_ICMPV6;
+                       hdr->hop_limit = 255;
+                       hdr->saddr = *saddr;
+                       hdr->daddr = *daddr;
+
+                       send_skb->transport_header = send_skb->tail;
+                       skb_put(send_skb, size);
+
+                       icmp6h = (struct icmp6hdr *)skb_transport_header(skb);
+                       icmp6h->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+                       icmp6h->icmp6_router = 0;
+                       icmp6h->icmp6_solicited = 1;
+                       target = (struct in6_addr *)skb_transport_header(send_skb) + sizeof(struct icmp6hdr);
+                       *target = msg->target;
+                       icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, size,
+                                                             IPPROTO_ICMPV6,
+                                                             csum_partial(icmp6h,
+                                                                          size, 0));
+
+                       if (dev_hard_header(send_skb, skb->dev, ETH_P_IPV6,
+                                           lladdr, np->dev->dev_addr,
+                                           send_skb->len) < 0) {
+                               kfree_skb(send_skb);
+                               continue;
+                       }
+
+                       netpoll_send_skb(np, send_skb);
+
+                       /* If there are several rx_hooks for the same address,
+                          we're fine by sending a single reply */
+                       break;
+               }
+               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+#endif
        }
-       spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+}
+
+static bool pkt_is_ns(struct sk_buff *skb)
+{
+       struct nd_msg *msg;
+       struct ipv6hdr *hdr;
+
+       if (skb->protocol != htons(ETH_P_ARP))
+               return false;
+       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)))
+               return false;
+
+       msg = (struct nd_msg *)skb_transport_header(skb);
+       __skb_push(skb, skb->data - skb_transport_header(skb));
+       hdr = ipv6_hdr(skb);
+
+       if (hdr->nexthdr != IPPROTO_ICMPV6)
+               return false;
+       if (hdr->hop_limit != 255)
+               return false;
+       if (msg->icmph.icmp6_code != 0)
+               return false;
+       if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
+               return false;
+
+       return true;
 }
 
 int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
@@ -571,9 +732,11 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
                goto out;
 
        /* check if netpoll clients need ARP */
-       if (skb->protocol == htons(ETH_P_ARP) &&
-           atomic_read(&trapped)) {
-               skb_queue_tail(&npinfo->arp_tx, skb);
+       if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) {
+               skb_queue_tail(&npinfo->neigh_tx, skb);
+               return 1;
+       } else if (pkt_is_ns(skb) && atomic_read(&trapped)) {
+               skb_queue_tail(&npinfo->neigh_tx, skb);
                return 1;
        }
 
@@ -584,60 +747,100 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
        }
 
        proto = ntohs(eth_hdr(skb)->h_proto);
-       if (proto != ETH_P_IP)
+       if (proto != ETH_P_IP && proto != ETH_P_IPV6)
                goto out;
        if (skb->pkt_type == PACKET_OTHERHOST)
                goto out;
        if (skb_shared(skb))
                goto out;
 
-       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-               goto out;
-       iph = (struct iphdr *)skb->data;
-       if (iph->ihl < 5 || iph->version != 4)
-               goto out;
-       if (!pskb_may_pull(skb, iph->ihl*4))
-               goto out;
-       iph = (struct iphdr *)skb->data;
-       if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-               goto out;
-
-       len = ntohs(iph->tot_len);
-       if (skb->len < len || len < iph->ihl*4)
-               goto out;
+       if (proto == ETH_P_IP) {
+               if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+                       goto out;
+               iph = (struct iphdr *)skb->data;
+               if (iph->ihl < 5 || iph->version != 4)
+                       goto out;
+               if (!pskb_may_pull(skb, iph->ihl*4))
+                       goto out;
+               iph = (struct iphdr *)skb->data;
+               if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+                       goto out;
 
-       /*
-        * Our transport medium may have padded the buffer out.
-        * Now We trim to the true length of the frame.
-        */
-       if (pskb_trim_rcsum(skb, len))
-               goto out;
+               len = ntohs(iph->tot_len);
+               if (skb->len < len || len < iph->ihl*4)
+                       goto out;
 
-       iph = (struct iphdr *)skb->data;
-       if (iph->protocol != IPPROTO_UDP)
-               goto out;
+               /*
+                * Our transport medium may have padded the buffer out.
+                * Now We trim to the true length of the frame.
+                */
+               if (pskb_trim_rcsum(skb, len))
+                       goto out;
 
-       len -= iph->ihl*4;
-       uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
-       ulen = ntohs(uh->len);
+               iph = (struct iphdr *)skb->data;
+               if (iph->protocol != IPPROTO_UDP)
+                       goto out;
 
-       if (ulen != len)
-               goto out;
-       if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
-               goto out;
+               len -= iph->ihl*4;
+               uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
+               ulen = ntohs(uh->len);
 
-       list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-               if (np->local_ip && np->local_ip != iph->daddr)
-                       continue;
-               if (np->remote_ip && np->remote_ip != iph->saddr)
-                       continue;
-               if (np->local_port && np->local_port != ntohs(uh->dest))
-                       continue;
+               if (ulen != len)
+                       goto out;
+               if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
+                       goto out;
+               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+                       if (np->local_ip.ip && np->local_ip.ip != iph->daddr)
+                               continue;
+                       if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
+                               continue;
+                       if (np->local_port && np->local_port != ntohs(uh->dest))
+                               continue;
+
+                       np->rx_hook(np, ntohs(uh->source),
+                                      (char *)(uh+1),
+                                      ulen - sizeof(struct udphdr));
+                       hits++;
+               }
+       } else {
+#if IS_ENABLED(CONFIG_IPV6)
+               const struct ipv6hdr *ip6h;
 
-               np->rx_hook(np, ntohs(uh->source),
-                              (char *)(uh+1),
-                              ulen - sizeof(struct udphdr));
-               hits++;
+               if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+                       goto out;
+               ip6h = (struct ipv6hdr *)skb->data;
+               if (ip6h->version != 6)
+                       goto out;
+               len = ntohs(ip6h->payload_len);
+               if (!len)
+                       goto out;
+               if (len + sizeof(struct ipv6hdr) > skb->len)
+                       goto out;
+               if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr)))
+                       goto out;
+               ip6h = ipv6_hdr(skb);
+               if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+                       goto out;
+               uh = udp_hdr(skb);
+               ulen = ntohs(uh->len);
+               if (ulen != skb->len)
+                       goto out;
+               if (udp6_csum_init(skb, uh, IPPROTO_UDP))
+                       goto out;
+               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+                       if (!ipv6_addr_equal(&np->local_ip.in6, &ip6h->daddr))
+                               continue;
+                       if (!ipv6_addr_equal(&np->remote_ip.in6, &ip6h->saddr))
+                               continue;
+                       if (np->local_port && np->local_port != ntohs(uh->dest))
+                               continue;
+
+                       np->rx_hook(np, ntohs(uh->source),
+                                      (char *)(uh+1),
+                                      ulen - sizeof(struct udphdr));
+                       hits++;
+               }
+#endif
        }
 
        if (!hits)
@@ -658,17 +861,44 @@ out:
 void netpoll_print_options(struct netpoll *np)
 {
        np_info(np, "local port %d\n", np->local_port);
-       np_info(np, "local IP %pI4\n", &np->local_ip);
+       if (np->ipv6)
+               np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
+       else
+               np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
        np_info(np, "interface '%s'\n", np->dev_name);
        np_info(np, "remote port %d\n", np->remote_port);
-       np_info(np, "remote IP %pI4\n", &np->remote_ip);
+       if (np->ipv6)
+               np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
+       else
+               np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
        np_info(np, "remote ethernet address %pM\n", np->remote_mac);
 }
 EXPORT_SYMBOL(netpoll_print_options);
 
+static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)
+{
+       const char *end;
+
+       if (!strchr(str, ':') &&
+           in4_pton(str, -1, (void *)addr, -1, &end) > 0) {
+               if (!*end)
+                       return 0;
+       }
+       if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) {
+#if IS_ENABLED(CONFIG_IPV6)
+               if (!*end)
+                       return 1;
+#else
+               return -1;
+#endif
+       }
+       return -1;
+}
+
 int netpoll_parse_options(struct netpoll *np, char *opt)
 {
        char *cur=opt, *delim;
+       int ipv6;
 
        if (*cur != '@') {
                if ((delim = strchr(cur, '@')) == NULL)
@@ -684,7 +914,11 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
                if ((delim = strchr(cur, '/')) == NULL)
                        goto parse_failed;
                *delim = 0;
-               np->local_ip = in_aton(cur);
+               ipv6 = netpoll_parse_ip_addr(cur, &np->local_ip);
+               if (ipv6 < 0)
+                       goto parse_failed;
+               else
+                       np->ipv6 = (bool)ipv6;
                cur = delim;
        }
        cur++;
@@ -716,7 +950,13 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
        if ((delim = strchr(cur, '/')) == NULL)
                goto parse_failed;
        *delim = 0;
-       np->remote_ip = in_aton(cur);
+       ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip);
+       if (ipv6 < 0)
+               goto parse_failed;
+       else if (np->ipv6 != (bool)ipv6)
+               goto parse_failed;
+       else
+               np->ipv6 = (bool)ipv6;
        cur = delim + 1;
 
        if (*cur != 0) {
@@ -764,7 +1004,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
                INIT_LIST_HEAD(&npinfo->rx_np);
 
                spin_lock_init(&npinfo->rx_lock);
-               skb_queue_head_init(&npinfo->arp_tx);
+               skb_queue_head_init(&npinfo->neigh_tx);
                skb_queue_head_init(&npinfo->txq);
                INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
 
@@ -808,14 +1048,19 @@ int netpoll_setup(struct netpoll *np)
        struct in_device *in_dev;
        int err;
 
-       if (np->dev_name)
-               ndev = dev_get_by_name(&init_net, np->dev_name);
+       rtnl_lock();
+       if (np->dev_name) {
+               struct net *net = current->nsproxy->net_ns;
+               ndev = __dev_get_by_name(net, np->dev_name);
+       }
        if (!ndev) {
                np_err(np, "%s doesn't exist, aborting\n", np->dev_name);
-               return -ENODEV;
+               err = -ENODEV;
+               goto unlock;
        }
+       dev_hold(ndev);
 
-       if (ndev->master) {
+       if (netdev_master_upper_dev_get(ndev)) {
                np_err(np, "%s is a slave device, aborting\n", np->dev_name);
                err = -EBUSY;
                goto put;
@@ -826,15 +1071,14 @@ int netpoll_setup(struct netpoll *np)
 
                np_info(np, "device %s not up yet, forcing it\n", np->dev_name);
 
-               rtnl_lock();
                err = dev_open(ndev);
-               rtnl_unlock();
 
                if (err) {
                        np_err(np, "failed to open %s\n", ndev->name);
                        goto put;
                }
 
+               rtnl_unlock();
                atleast = jiffies + HZ/10;
                atmost = jiffies + carrier_timeout * HZ;
                while (!netif_carrier_ok(ndev)) {
@@ -854,39 +1098,70 @@ int netpoll_setup(struct netpoll *np)
                        np_notice(np, "carrier detect appears untrustworthy, waiting 4 seconds\n");
                        msleep(4000);
                }
+               rtnl_lock();
        }
 
-       if (!np->local_ip) {
-               rcu_read_lock();
-               in_dev = __in_dev_get_rcu(ndev);
+       if (!np->local_ip.ip) {
+               if (!np->ipv6) {
+                       in_dev = __in_dev_get_rtnl(ndev);
+
+                       if (!in_dev || !in_dev->ifa_list) {
+                               np_err(np, "no IP address for %s, aborting\n",
+                                      np->dev_name);
+                               err = -EDESTADDRREQ;
+                               goto put;
+                       }
+
+                       np->local_ip.ip = in_dev->ifa_list->ifa_local;
+                       np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+               } else {
+#if IS_ENABLED(CONFIG_IPV6)
+                       struct inet6_dev *idev;
 
-               if (!in_dev || !in_dev->ifa_list) {
-                       rcu_read_unlock();
-                       np_err(np, "no IP address for %s, aborting\n",
-                              np->dev_name);
                        err = -EDESTADDRREQ;
+                       idev = __in6_dev_get(ndev);
+                       if (idev) {
+                               struct inet6_ifaddr *ifp;
+
+                               read_lock_bh(&idev->lock);
+                               list_for_each_entry(ifp, &idev->addr_list, if_list) {
+                                       if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)
+                                               continue;
+                                       np->local_ip.in6 = ifp->addr;
+                                       err = 0;
+                                       break;
+                               }
+                               read_unlock_bh(&idev->lock);
+                       }
+                       if (err) {
+                               np_err(np, "no IPv6 address for %s, aborting\n",
+                                      np->dev_name);
+                               goto put;
+                       } else
+                               np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
+#else
+                       np_err(np, "IPv6 is not supported %s, aborting\n",
+                              np->dev_name);
+                       err = -EINVAL;
                        goto put;
+#endif
                }
-
-               np->local_ip = in_dev->ifa_list->ifa_local;
-               rcu_read_unlock();
-               np_info(np, "local IP %pI4\n", &np->local_ip);
        }
 
        /* fill up the skb queue */
        refill_skbs();
 
-       rtnl_lock();
        err = __netpoll_setup(np, ndev, GFP_KERNEL);
-       rtnl_unlock();
-
        if (err)
                goto put;
 
+       rtnl_unlock();
        return 0;
 
 put:
        dev_put(ndev);
+unlock:
+       rtnl_unlock();
        return err;
 }
 EXPORT_SYMBOL(netpoll_setup);
@@ -903,7 +1178,7 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
        struct netpoll_info *npinfo =
                        container_of(rcu_head, struct netpoll_info, rcu);
 
-       skb_queue_purge(&npinfo->arp_tx);
+       skb_queue_purge(&npinfo->neigh_tx);
        skb_queue_purge(&npinfo->txq);
 
        /* we can't call cancel_delayed_work_sync here, as we are in softirq */
index b29dacf900f9496a42a565a3b2c48ad9cf502c74..797769551b91181421a6622ddbe7de46f9d107a0 100644 (file)
 #ifdef CONFIG_XFRM
 #include <net/xfrm.h>
 #endif
+#include <net/netns/generic.h>
 #include <asm/byteorder.h>
 #include <linux/rcupdate.h>
 #include <linux/bitops.h>
 #define PKTGEN_MAGIC 0xbe9be955
 #define PG_PROC_DIR "pktgen"
 #define PGCTRL     "pgctrl"
-static struct proc_dir_entry *pg_proc_dir;
 
 #define MAX_CFLOWS  65536
 
@@ -397,7 +397,15 @@ struct pktgen_hdr {
        __be32 tv_usec;
 };
 
-static bool pktgen_exiting __read_mostly;
+
+static int pg_net_id __read_mostly;
+
+struct pktgen_net {
+       struct net              *net;
+       struct proc_dir_entry   *proc_dir;
+       struct list_head        pktgen_threads;
+       bool                    pktgen_exiting;
+};
 
 struct pktgen_thread {
        spinlock_t if_lock;             /* for list of devices */
@@ -414,6 +422,7 @@ struct pktgen_thread {
 
        wait_queue_head_t queue;
        struct completion start_done;
+       struct pktgen_net *net;
 };
 
 #define REMOVE 1
@@ -428,9 +437,9 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
 static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
                                          const char *ifname, bool exact);
 static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
-static void pktgen_run_all_threads(void);
-static void pktgen_reset_all_threads(void);
-static void pktgen_stop_all_threads_ifs(void);
+static void pktgen_run_all_threads(struct pktgen_net *pn);
+static void pktgen_reset_all_threads(struct pktgen_net *pn);
+static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn);
 
 static void pktgen_stop(struct pktgen_thread *t);
 static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
@@ -442,7 +451,6 @@ static int pg_clone_skb_d  __read_mostly;
 static int debug  __read_mostly;
 
 static DEFINE_MUTEX(pktgen_thread_lock);
-static LIST_HEAD(pktgen_threads);
 
 static struct notifier_block pktgen_notifier_block = {
        .notifier_call = pktgen_device_event,
@@ -464,6 +472,7 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf,
 {
        int err = 0;
        char data[128];
+       struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id);
 
        if (!capable(CAP_NET_ADMIN)) {
                err = -EPERM;
@@ -480,13 +489,13 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf,
        data[count - 1] = 0;    /* Make string */
 
        if (!strcmp(data, "stop"))
-               pktgen_stop_all_threads_ifs();
+               pktgen_stop_all_threads_ifs(pn);
 
        else if (!strcmp(data, "start"))
-               pktgen_run_all_threads();
+               pktgen_run_all_threads(pn);
 
        else if (!strcmp(data, "reset"))
-               pktgen_reset_all_threads();
+               pktgen_reset_all_threads(pn);
 
        else
                pr_warning("Unknown command: %s\n", data);
@@ -1824,13 +1833,14 @@ static const struct file_operations pktgen_thread_fops = {
 };
 
 /* Think find or remove for NN */
-static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
+static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn,
+                                             const char *ifname, int remove)
 {
        struct pktgen_thread *t;
        struct pktgen_dev *pkt_dev = NULL;
        bool exact = (remove == FIND);
 
-       list_for_each_entry(t, &pktgen_threads, th_list) {
+       list_for_each_entry(t, &pn->pktgen_threads, th_list) {
                pkt_dev = pktgen_find_dev(t, ifname, exact);
                if (pkt_dev) {
                        if (remove) {
@@ -1848,7 +1858,7 @@ static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
 /*
  * mark a device for removal
  */
-static void pktgen_mark_device(const char *ifname)
+static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname)
 {
        struct pktgen_dev *pkt_dev = NULL;
        const int max_tries = 10, msec_per_try = 125;
@@ -1859,7 +1869,7 @@ static void pktgen_mark_device(const char *ifname)
 
        while (1) {
 
-               pkt_dev = __pktgen_NN_threads(ifname, REMOVE);
+               pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE);
                if (pkt_dev == NULL)
                        break;  /* success */
 
@@ -1880,21 +1890,21 @@ static void pktgen_mark_device(const char *ifname)
        mutex_unlock(&pktgen_thread_lock);
 }
 
-static void pktgen_change_name(struct net_device *dev)
+static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev)
 {
        struct pktgen_thread *t;
 
-       list_for_each_entry(t, &pktgen_threads, th_list) {
+       list_for_each_entry(t, &pn->pktgen_threads, th_list) {
                struct pktgen_dev *pkt_dev;
 
                list_for_each_entry(pkt_dev, &t->if_list, list) {
                        if (pkt_dev->odev != dev)
                                continue;
 
-                       remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
+                       remove_proc_entry(pkt_dev->entry->name, pn->proc_dir);
 
                        pkt_dev->entry = proc_create_data(dev->name, 0600,
-                                                         pg_proc_dir,
+                                                         pn->proc_dir,
                                                          &pktgen_if_fops,
                                                          pkt_dev);
                        if (!pkt_dev->entry)
@@ -1909,8 +1919,9 @@ static int pktgen_device_event(struct notifier_block *unused,
                               unsigned long event, void *ptr)
 {
        struct net_device *dev = ptr;
+       struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id);
 
-       if (!net_eq(dev_net(dev), &init_net) || pktgen_exiting)
+       if (pn->pktgen_exiting)
                return NOTIFY_DONE;
 
        /* It is OK that we do not hold the group lock right now,
@@ -1919,18 +1930,19 @@ static int pktgen_device_event(struct notifier_block *unused,
 
        switch (event) {
        case NETDEV_CHANGENAME:
-               pktgen_change_name(dev);
+               pktgen_change_name(pn, dev);
                break;
 
        case NETDEV_UNREGISTER:
-               pktgen_mark_device(dev->name);
+               pktgen_mark_device(pn, dev->name);
                break;
        }
 
        return NOTIFY_DONE;
 }
 
-static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,
+static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn,
+                                                struct pktgen_dev *pkt_dev,
                                                 const char *ifname)
 {
        char b[IFNAMSIZ+5];
@@ -1944,13 +1956,14 @@ static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,
        }
        b[i] = 0;
 
-       return dev_get_by_name(&init_net, b);
+       return dev_get_by_name(pn->net, b);
 }
 
 
 /* Associate pktgen_dev with a device. */
 
-static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
+static int pktgen_setup_dev(const struct pktgen_net *pn,
+                           struct pktgen_dev *pkt_dev, const char *ifname)
 {
        struct net_device *odev;
        int err;
@@ -1961,7 +1974,7 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
                pkt_dev->odev = NULL;
        }
 
-       odev = pktgen_dev_get_by_name(pkt_dev, ifname);
+       odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname);
        if (!odev) {
                pr_err("no such netdevice: \"%s\"\n", ifname);
                return -ENODEV;
@@ -2203,9 +2216,10 @@ static inline int f_pick(struct pktgen_dev *pkt_dev)
 static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
 {
        struct xfrm_state *x = pkt_dev->flows[flow].x;
+       struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
        if (!x) {
                /*slow path: we dont already have xfrm_state*/
-               x = xfrm_stateonly_find(&init_net, DUMMY_MARK,
+               x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
                                        (xfrm_address_t *)&pkt_dev->cur_daddr,
                                        (xfrm_address_t *)&pkt_dev->cur_saddr,
                                        AF_INET,
@@ -2912,7 +2926,7 @@ static void pktgen_run(struct pktgen_thread *t)
                t->control &= ~(T_STOP);
 }
 
-static void pktgen_stop_all_threads_ifs(void)
+static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn)
 {
        struct pktgen_thread *t;
 
@@ -2920,7 +2934,7 @@ static void pktgen_stop_all_threads_ifs(void)
 
        mutex_lock(&pktgen_thread_lock);
 
-       list_for_each_entry(t, &pktgen_threads, th_list)
+       list_for_each_entry(t, &pn->pktgen_threads, th_list)
                t->control |= T_STOP;
 
        mutex_unlock(&pktgen_thread_lock);
@@ -2956,28 +2970,28 @@ signal:
        return 0;
 }
 
-static int pktgen_wait_all_threads_run(void)
+static int pktgen_wait_all_threads_run(struct pktgen_net *pn)
 {
        struct pktgen_thread *t;
        int sig = 1;
 
        mutex_lock(&pktgen_thread_lock);
 
-       list_for_each_entry(t, &pktgen_threads, th_list) {
+       list_for_each_entry(t, &pn->pktgen_threads, th_list) {
                sig = pktgen_wait_thread_run(t);
                if (sig == 0)
                        break;
        }
 
        if (sig == 0)
-               list_for_each_entry(t, &pktgen_threads, th_list)
+               list_for_each_entry(t, &pn->pktgen_threads, th_list)
                        t->control |= (T_STOP);
 
        mutex_unlock(&pktgen_thread_lock);
        return sig;
 }
 
-static void pktgen_run_all_threads(void)
+static void pktgen_run_all_threads(struct pktgen_net *pn)
 {
        struct pktgen_thread *t;
 
@@ -2985,7 +2999,7 @@ static void pktgen_run_all_threads(void)
 
        mutex_lock(&pktgen_thread_lock);
 
-       list_for_each_entry(t, &pktgen_threads, th_list)
+       list_for_each_entry(t, &pn->pktgen_threads, th_list)
                t->control |= (T_RUN);
 
        mutex_unlock(&pktgen_thread_lock);
@@ -2993,10 +3007,10 @@ static void pktgen_run_all_threads(void)
        /* Propagate thread->control  */
        schedule_timeout_interruptible(msecs_to_jiffies(125));
 
-       pktgen_wait_all_threads_run();
+       pktgen_wait_all_threads_run(pn);
 }
 
-static void pktgen_reset_all_threads(void)
+static void pktgen_reset_all_threads(struct pktgen_net *pn)
 {
        struct pktgen_thread *t;
 
@@ -3004,7 +3018,7 @@ static void pktgen_reset_all_threads(void)
 
        mutex_lock(&pktgen_thread_lock);
 
-       list_for_each_entry(t, &pktgen_threads, th_list)
+       list_for_each_entry(t, &pn->pktgen_threads, th_list)
                t->control |= (T_REMDEVALL);
 
        mutex_unlock(&pktgen_thread_lock);
@@ -3012,7 +3026,7 @@ static void pktgen_reset_all_threads(void)
        /* Propagate thread->control  */
        schedule_timeout_interruptible(msecs_to_jiffies(125));
 
-       pktgen_wait_all_threads_run();
+       pktgen_wait_all_threads_run(pn);
 }
 
 static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
@@ -3154,9 +3168,7 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t)
 static void pktgen_rem_thread(struct pktgen_thread *t)
 {
        /* Remove from the thread list */
-
-       remove_proc_entry(t->tsk->comm, pg_proc_dir);
-
+       remove_proc_entry(t->tsk->comm, t->net->proc_dir);
 }
 
 static void pktgen_resched(struct pktgen_dev *pkt_dev)
@@ -3302,7 +3314,7 @@ static int pktgen_thread_worker(void *arg)
                pkt_dev = next_to_run(t);
 
                if (unlikely(!pkt_dev && t->control == 0)) {
-                       if (pktgen_exiting)
+                       if (t->net->pktgen_exiting)
                                break;
                        wait_event_interruptible_timeout(t->queue,
                                                         t->control != 0,
@@ -3424,7 +3436,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 
        /* We don't allow a device to be on several threads */
 
-       pkt_dev = __pktgen_NN_threads(ifname, FIND);
+       pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND);
        if (pkt_dev) {
                pr_err("ERROR: interface already used\n");
                return -EBUSY;
@@ -3459,13 +3471,13 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        pkt_dev->svlan_id = 0xffff;
        pkt_dev->node = -1;
 
-       err = pktgen_setup_dev(pkt_dev, ifname);
+       err = pktgen_setup_dev(t->net, pkt_dev, ifname);
        if (err)
                goto out1;
        if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)
                pkt_dev->clone_skb = pg_clone_skb_d;
 
-       pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
+       pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir,
                                          &pktgen_if_fops, pkt_dev);
        if (!pkt_dev->entry) {
                pr_err("cannot create %s/%s procfs entry\n",
@@ -3490,7 +3502,7 @@ out1:
        return err;
 }
 
-static int __init pktgen_create_thread(int cpu)
+static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
 {
        struct pktgen_thread *t;
        struct proc_dir_entry *pe;
@@ -3508,7 +3520,7 @@ static int __init pktgen_create_thread(int cpu)
 
        INIT_LIST_HEAD(&t->if_list);
 
-       list_add_tail(&t->th_list, &pktgen_threads);
+       list_add_tail(&t->th_list, &pn->pktgen_threads);
        init_completion(&t->start_done);
 
        p = kthread_create_on_node(pktgen_thread_worker,
@@ -3524,7 +3536,7 @@ static int __init pktgen_create_thread(int cpu)
        kthread_bind(p, cpu);
        t->tsk = p;
 
-       pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir,
+       pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir,
                              &pktgen_thread_fops, t);
        if (!pe) {
                pr_err("cannot create %s/%s procfs entry\n",
@@ -3535,6 +3547,7 @@ static int __init pktgen_create_thread(int cpu)
                return -EINVAL;
        }
 
+       t->net = pn;
        wake_up_process(p);
        wait_for_completion(&t->start_done);
 
@@ -3560,6 +3573,7 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t,
 static int pktgen_remove_device(struct pktgen_thread *t,
                                struct pktgen_dev *pkt_dev)
 {
+       struct pktgen_net *pn = t->net;
 
        pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
 
@@ -3580,7 +3594,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,
        _rem_dev_from_if_list(t, pkt_dev);
 
        if (pkt_dev->entry)
-               remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
+               remove_proc_entry(pkt_dev->entry->name, pn->proc_dir);
 
 #ifdef CONFIG_XFRM
        free_SAs(pkt_dev);
@@ -3592,63 +3606,63 @@ static int pktgen_remove_device(struct pktgen_thread *t,
        return 0;
 }
 
-static int __init pg_init(void)
+static int __net_init pg_net_init(struct net *net)
 {
-       int cpu;
+       struct pktgen_net *pn = net_generic(net, pg_net_id);
        struct proc_dir_entry *pe;
-       int ret = 0;
-
-       pr_info("%s", version);
-
-       pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
-       if (!pg_proc_dir)
+       int cpu, ret = 0;
+
+       pn->net = net;
+       INIT_LIST_HEAD(&pn->pktgen_threads);
+       pn->pktgen_exiting = false;
+       pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net);
+       if (!pn->proc_dir) {
+               pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR);
                return -ENODEV;
-
-       pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
+       }
+       pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_fops);
        if (pe == NULL) {
-               pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL);
+               pr_err("cannot create %s procfs entry\n", PGCTRL);
                ret = -EINVAL;
-               goto remove_dir;
+               goto remove;
        }
 
-       register_netdevice_notifier(&pktgen_notifier_block);
-
        for_each_online_cpu(cpu) {
                int err;
 
-               err = pktgen_create_thread(cpu);
+               err = pktgen_create_thread(cpu, pn);
                if (err)
-                       pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n",
+                       pr_warn("Cannot create thread for cpu %d (%d)\n",
                                   cpu, err);
        }
 
-       if (list_empty(&pktgen_threads)) {
-               pr_err("ERROR: Initialization failed for all threads\n");
+       if (list_empty(&pn->pktgen_threads)) {
+               pr_err("Initialization failed for all threads\n");
                ret = -ENODEV;
-               goto unregister;
+               goto remove_entry;
        }
 
        return 0;
 
- unregister:
-       unregister_netdevice_notifier(&pktgen_notifier_block);
-       remove_proc_entry(PGCTRL, pg_proc_dir);
- remove_dir:
-       proc_net_remove(&init_net, PG_PROC_DIR);
+remove_entry:
+       remove_proc_entry(PGCTRL, pn->proc_dir);
+remove:
+       proc_net_remove(pn->net, PG_PROC_DIR);
        return ret;
 }
 
-static void __exit pg_cleanup(void)
+static void __net_exit pg_net_exit(struct net *net)
 {
+       struct pktgen_net *pn = net_generic(net, pg_net_id);
        struct pktgen_thread *t;
        struct list_head *q, *n;
        LIST_HEAD(list);
 
        /* Stop all interfaces & threads */
-       pktgen_exiting = true;
+       pn->pktgen_exiting = true;
 
        mutex_lock(&pktgen_thread_lock);
-       list_splice_init(&pktgen_threads, &list);
+       list_splice_init(&pn->pktgen_threads, &list);
        mutex_unlock(&pktgen_thread_lock);
 
        list_for_each_safe(q, n, &list) {
@@ -3658,12 +3672,36 @@ static void __exit pg_cleanup(void)
                kfree(t);
        }
 
-       /* Un-register us from receiving netdevice events */
-       unregister_netdevice_notifier(&pktgen_notifier_block);
+       remove_proc_entry(PGCTRL, pn->proc_dir);
+       proc_net_remove(pn->net, PG_PROC_DIR);
+}
+
+static struct pernet_operations pg_net_ops = {
+       .init = pg_net_init,
+       .exit = pg_net_exit,
+       .id   = &pg_net_id,
+       .size = sizeof(struct pktgen_net),
+};
+
+static int __init pg_init(void)
+{
+       int ret = 0;
 
-       /* Clean up proc file system */
-       remove_proc_entry(PGCTRL, pg_proc_dir);
-       proc_net_remove(&init_net, PG_PROC_DIR);
+       pr_info("%s", version);
+       ret = register_pernet_subsys(&pg_net_ops);
+       if (ret)
+               return ret;
+       ret = register_netdevice_notifier(&pktgen_notifier_block);
+       if (ret)
+               unregister_pernet_subsys(&pg_net_ops);
+
+       return ret;
+}
+
+static void __exit pg_cleanup(void)
+{
+       unregister_netdevice_notifier(&pktgen_notifier_block);
+       unregister_pernet_subsys(&pg_net_ops);
 }
 
 module_init(pg_init);
index 1868625af25e096d1c7886d29ce6c5967ac1040f..9a419b0994822986c90abacf1ebe49307618ed1b 100644 (file)
@@ -780,6 +780,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
               + nla_total_size(4) /* IFLA_MTU */
               + nla_total_size(4) /* IFLA_LINK */
               + nla_total_size(4) /* IFLA_MASTER */
+              + nla_total_size(1) /* IFLA_CARRIER */
               + nla_total_size(4) /* IFLA_PROMISCUITY */
               + nla_total_size(4) /* IFLA_NUM_TX_QUEUES */
               + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */
@@ -879,6 +880,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        const struct rtnl_link_stats64 *stats;
        struct nlattr *attr, *af_spec;
        struct rtnl_af_ops *af_ops;
+       struct net_device *upper_dev = netdev_master_upper_dev_get(dev);
 
        ASSERT_RTNL();
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
@@ -907,8 +909,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
 #endif
            (dev->ifindex != dev->iflink &&
             nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
-           (dev->master &&
-            nla_put_u32(skb, IFLA_MASTER, dev->master->ifindex)) ||
+           (upper_dev &&
+            nla_put_u32(skb, IFLA_MASTER, upper_dev->ifindex)) ||
+           nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) ||
            (dev->qdisc &&
             nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) ||
            (dev->ifalias &&
@@ -1108,6 +1111,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_MTU]              = { .type = NLA_U32 },
        [IFLA_LINK]             = { .type = NLA_U32 },
        [IFLA_MASTER]           = { .type = NLA_U32 },
+       [IFLA_CARRIER]          = { .type = NLA_U8 },
        [IFLA_TXQLEN]           = { .type = NLA_U32 },
        [IFLA_WEIGHT]           = { .type = NLA_U32 },
        [IFLA_OPERSTATE]        = { .type = NLA_U8 },
@@ -1270,16 +1274,16 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
 
 static int do_set_master(struct net_device *dev, int ifindex)
 {
-       struct net_device *master_dev;
+       struct net_device *upper_dev = netdev_master_upper_dev_get(dev);
        const struct net_device_ops *ops;
        int err;
 
-       if (dev->master) {
-               if (dev->master->ifindex == ifindex)
+       if (upper_dev) {
+               if (upper_dev->ifindex == ifindex)
                        return 0;
-               ops = dev->master->netdev_ops;
+               ops = upper_dev->netdev_ops;
                if (ops->ndo_del_slave) {
-                       err = ops->ndo_del_slave(dev->master, dev);
+                       err = ops->ndo_del_slave(upper_dev, dev);
                        if (err)
                                return err;
                } else {
@@ -1288,12 +1292,12 @@ static int do_set_master(struct net_device *dev, int ifindex)
        }
 
        if (ifindex) {
-               master_dev = __dev_get_by_index(dev_net(dev), ifindex);
-               if (!master_dev)
+               upper_dev = __dev_get_by_index(dev_net(dev), ifindex);
+               if (!upper_dev)
                        return -EINVAL;
-               ops = master_dev->netdev_ops;
+               ops = upper_dev->netdev_ops;
                if (ops->ndo_add_slave) {
-                       err = ops->ndo_add_slave(master_dev, dev);
+                       err = ops->ndo_add_slave(upper_dev, dev);
                        if (err)
                                return err;
                } else {
@@ -1307,7 +1311,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                      struct nlattr **tb, char *ifname, int modified)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
-       int send_addr_notify = 0;
        int err;
 
        if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) {
@@ -1360,16 +1363,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                struct sockaddr *sa;
                int len;
 
-               if (!ops->ndo_set_mac_address) {
-                       err = -EOPNOTSUPP;
-                       goto errout;
-               }
-
-               if (!netif_device_present(dev)) {
-                       err = -ENODEV;
-                       goto errout;
-               }
-
                len = sizeof(sa_family_t) + dev->addr_len;
                sa = kmalloc(len, GFP_KERNEL);
                if (!sa) {
@@ -1379,13 +1372,11 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                sa->sa_family = dev->type;
                memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
                       dev->addr_len);
-               err = ops->ndo_set_mac_address(dev, sa);
+               err = dev_set_mac_address(dev, sa);
                kfree(sa);
                if (err)
                        goto errout;
-               send_addr_notify = 1;
                modified = 1;
-               add_device_randomness(dev->dev_addr, dev->addr_len);
        }
 
        if (tb[IFLA_MTU]) {
@@ -1422,7 +1413,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
 
        if (tb[IFLA_BROADCAST]) {
                nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
-               send_addr_notify = 1;
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
        }
 
        if (ifm->ifi_flags || ifm->ifi_change) {
@@ -1438,6 +1429,13 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                modified = 1;
        }
 
+       if (tb[IFLA_CARRIER]) {
+               err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER]));
+               if (err)
+                       goto errout;
+               modified = 1;
+       }
+
        if (tb[IFLA_TXQLEN])
                dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
 
@@ -1536,9 +1534,6 @@ errout:
                net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n",
                                     dev->name);
 
-       if (send_addr_notify)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
-
        return err;
 }
 
@@ -1672,9 +1667,11 @@ struct net_device *rtnl_create_link(struct net *net,
 
        if (tb[IFLA_MTU])
                dev->mtu = nla_get_u32(tb[IFLA_MTU]);
-       if (tb[IFLA_ADDRESS])
+       if (tb[IFLA_ADDRESS]) {
                memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
                                nla_len(tb[IFLA_ADDRESS]));
+               dev->addr_assign_type = NET_ADDR_SET;
+       }
        if (tb[IFLA_BROADCAST])
                memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
                                nla_len(tb[IFLA_BROADCAST]));
@@ -1992,6 +1989,7 @@ errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
 }
+EXPORT_SYMBOL(rtmsg_ifinfo);
 
 static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
                                   struct net_device *dev,
@@ -2054,7 +2052,6 @@ errout:
 static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct net *net = sock_net(skb->sk);
-       struct net_device *master = NULL;
        struct ndmsg *ndm;
        struct nlattr *tb[NDA_MAX+1];
        struct net_device *dev;
@@ -2096,10 +2093,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        /* Support fdb on master device the net/bridge default case */
        if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) &&
            (dev->priv_flags & IFF_BRIDGE_PORT)) {
-               master = dev->master;
-               err = master->netdev_ops->ndo_fdb_add(ndm, tb,
-                                                     dev, addr,
-                                                     nlh->nlmsg_flags);
+               struct net_device *br_dev = netdev_master_upper_dev_get(dev);
+               const struct net_device_ops *ops = br_dev->netdev_ops;
+
+               err = ops->ndo_fdb_add(ndm, tb, dev, addr, nlh->nlmsg_flags);
                if (err)
                        goto out;
                else
@@ -2160,10 +2157,11 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        /* Support fdb on master device the net/bridge default case */
        if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) &&
            (dev->priv_flags & IFF_BRIDGE_PORT)) {
-               struct net_device *master = dev->master;
+               struct net_device *br_dev = netdev_master_upper_dev_get(dev);
+               const struct net_device_ops *ops = br_dev->netdev_ops;
 
-               if (master->netdev_ops->ndo_fdb_del)
-                       err = master->netdev_ops->ndo_fdb_del(ndm, dev, addr);
+               if (ops->ndo_fdb_del)
+                       err = ops->ndo_fdb_del(ndm, dev, addr);
 
                if (err)
                        goto out;
@@ -2247,9 +2245,11 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
        rcu_read_lock();
        for_each_netdev_rcu(net, dev) {
                if (dev->priv_flags & IFF_BRIDGE_PORT) {
-                       struct net_device *master = dev->master;
-                       const struct net_device_ops *ops = master->netdev_ops;
+                       struct net_device *br_dev;
+                       const struct net_device_ops *ops;
 
+                       br_dev = netdev_master_upper_dev_get(dev);
+                       ops = br_dev->netdev_ops;
                        if (ops->ndo_fdb_dump)
                                idx = ops->ndo_fdb_dump(skb, cb, dev, idx);
                }
@@ -2270,6 +2270,7 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
        struct ifinfomsg *ifm;
        struct nlattr *br_afspec;
        u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
+       struct net_device *br_dev = netdev_master_upper_dev_get(dev);
 
        nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), NLM_F_MULTI);
        if (nlh == NULL)
@@ -2287,8 +2288,8 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
        if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
            nla_put_u32(skb, IFLA_MTU, dev->mtu) ||
            nla_put_u8(skb, IFLA_OPERSTATE, operstate) ||
-           (dev->master &&
-            nla_put_u32(skb, IFLA_MASTER, dev->master->ifindex)) ||
+           (br_dev &&
+            nla_put_u32(skb, IFLA_MASTER, br_dev->ifindex)) ||
            (dev->addr_len &&
             nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
            (dev->ifindex != dev->iflink &&
@@ -2324,11 +2325,11 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
        rcu_read_lock();
        for_each_netdev_rcu(net, dev) {
                const struct net_device_ops *ops = dev->netdev_ops;
-               struct net_device *master = dev->master;
+               struct net_device *br_dev = netdev_master_upper_dev_get(dev);
 
-               if (master && master->netdev_ops->ndo_bridge_getlink) {
+               if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
                        if (idx >= cb->args[0] &&
-                           master->netdev_ops->ndo_bridge_getlink(
+                           br_dev->netdev_ops->ndo_bridge_getlink(
                                    skb, portid, seq, dev) < 0)
                                break;
                        idx++;
@@ -2365,7 +2366,7 @@ static inline size_t bridge_nlmsg_size(void)
 static int rtnl_bridge_notify(struct net_device *dev, u16 flags)
 {
        struct net *net = dev_net(dev);
-       struct net_device *master = dev->master;
+       struct net_device *br_dev = netdev_master_upper_dev_get(dev);
        struct sk_buff *skb;
        int err = -EOPNOTSUPP;
 
@@ -2376,8 +2377,8 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags)
        }
 
        if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) &&
-           master && master->netdev_ops->ndo_bridge_getlink) {
-               err = master->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
+           br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
+               err = br_dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
                if (err < 0)
                        goto errout;
        }
@@ -2436,13 +2437,14 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
        oflags = flags;
 
        if (!flags || (flags & BRIDGE_FLAGS_MASTER)) {
-               if (!dev->master ||
-                   !dev->master->netdev_ops->ndo_bridge_setlink) {
+               struct net_device *br_dev = netdev_master_upper_dev_get(dev);
+
+               if (!br_dev || !br_dev->netdev_ops->ndo_bridge_setlink) {
                        err = -EOPNOTSUPP;
                        goto out;
                }
 
-               err = dev->master->netdev_ops->ndo_bridge_setlink(dev, nlh);
+               err = br_dev->netdev_ops->ndo_bridge_setlink(dev, nlh);
                if (err)
                        goto out;
 
index a9a2ae3e2213a3769bd79df65229822768c09264..bddc1dd2e7f221331136aec6e4b6efebdf4feb2c 100644 (file)
@@ -155,8 +155,9 @@ static void skb_under_panic(struct sk_buff *skb, int sz, void *here)
  */
 #define kmalloc_reserve(size, gfp, node, pfmemalloc) \
         __kmalloc_reserve(size, gfp, node, _RET_IP_, pfmemalloc)
-void *__kmalloc_reserve(size_t size, gfp_t flags, int node, unsigned long ip,
-                        bool *pfmemalloc)
+
+static void *__kmalloc_reserve(size_t size, gfp_t flags, int node,
+                              unsigned long ip, bool *pfmemalloc)
 {
        void *obj;
        bool ret_pfmemalloc = false;
@@ -259,6 +260,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        skb->end = skb->tail + size;
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
        skb->mac_header = ~0U;
+       skb->transport_header = ~0U;
 #endif
 
        /* make sure we initialize shinfo sequentially */
@@ -327,6 +329,7 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size)
        skb->end = skb->tail + size;
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
        skb->mac_header = ~0U;
+       skb->transport_header = ~0U;
 #endif
 
        /* make sure we initialize shinfo sequentially */
@@ -2337,6 +2340,8 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
 {
        int pos = skb_headlen(skb);
 
+       skb_shinfo(skb1)->gso_type = skb_shinfo(skb)->gso_type;
+
        if (len < pos)  /* Split line is inside header. */
                skb_split_inside_header(skb, skb1, len, pos);
        else            /* Second chunk has no header, nothing to copy. */
@@ -2668,48 +2673,37 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
                                        int len, int odd, struct sk_buff *skb),
                        void *from, int length)
 {
-       int frg_cnt = 0;
-       skb_frag_t *frag = NULL;
-       struct page *page = NULL;
-       int copy, left;
+       int frg_cnt = skb_shinfo(skb)->nr_frags;
+       int copy;
        int offset = 0;
        int ret;
+       struct page_frag *pfrag = &current->task_frag;
 
        do {
                /* Return error if we don't have space for new frag */
-               frg_cnt = skb_shinfo(skb)->nr_frags;
                if (frg_cnt >= MAX_SKB_FRAGS)
-                       return -EFAULT;
-
-               /* allocate a new page for next frag */
-               page = alloc_pages(sk->sk_allocation, 0);
+                       return -EMSGSIZE;
 
-               /* If alloc_page fails just return failure and caller will
-                * free previous allocated pages by doing kfree_skb()
-                */
-               if (page == NULL)
+               if (!sk_page_frag_refill(sk, pfrag))
                        return -ENOMEM;
 
-               /* initialize the next frag */
-               skb_fill_page_desc(skb, frg_cnt, page, 0, 0);
-               skb->truesize += PAGE_SIZE;
-               atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
-
-               /* get the new initialized frag */
-               frg_cnt = skb_shinfo(skb)->nr_frags;
-               frag = &skb_shinfo(skb)->frags[frg_cnt - 1];
-
                /* copy the user data to page */
-               left = PAGE_SIZE - frag->page_offset;
-               copy = (length > left)? left : length;
+               copy = min_t(int, length, pfrag->size - pfrag->offset);
 
-               ret = getfrag(from, skb_frag_address(frag) + skb_frag_size(frag),
-                           offset, copy, 0, skb);
+               ret = getfrag(from, page_address(pfrag->page) + pfrag->offset,
+                             offset, copy, 0, skb);
                if (ret < 0)
                        return -EFAULT;
 
                /* copy was successful so update the size parameters */
-               skb_frag_size_add(frag, copy);
+               skb_fill_page_desc(skb, frg_cnt, pfrag->page, pfrag->offset,
+                                  copy);
+               frg_cnt++;
+               pfrag->offset += copy;
+               get_page(pfrag->page);
+
+               skb->truesize += copy;
+               atomic_add(copy, &sk->sk_wmem_alloc);
                skb->len += copy;
                skb->data_len += copy;
                offset += copy;
@@ -2853,6 +2847,8 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                skb_copy_from_linear_data_offset(skb, offset,
                                                 skb_put(nskb, hsize), hsize);
 
+               skb_shinfo(nskb)->gso_type = skb_shinfo(skb)->gso_type;
+
                while (pos < offset + len && i < nfrags) {
                        *frag = skb_shinfo(skb)->frags[i];
                        __skb_frag_ref(frag);
index bc131d419683c11bd6f098c930e7d4f3cd9fb697..235fb89e8973a864978c00acfa0dbc0173762082 100644 (file)
@@ -665,6 +665,9 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
        case SO_REUSEADDR:
                sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE);
                break;
+       case SO_REUSEPORT:
+               sk->sk_reuseport = valbool;
+               break;
        case SO_TYPE:
        case SO_PROTOCOL:
        case SO_DOMAIN:
@@ -861,6 +864,13 @@ set_rcvbuf:
                ret = sk_detach_filter(sk);
                break;
 
+       case SO_LOCK_FILTER:
+               if (sock_flag(sk, SOCK_FILTER_LOCKED) && !valbool)
+                       ret = -EPERM;
+               else
+                       sock_valbool_flag(sk, SOCK_FILTER_LOCKED, valbool);
+               break;
+
        case SO_PASSSEC:
                if (valbool)
                        set_bit(SOCK_PASSSEC, &sock->flags);
@@ -965,6 +975,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = sk->sk_reuse;
                break;
 
+       case SO_REUSEPORT:
+               v.val = sk->sk_reuseport;
+               break;
+
        case SO_KEEPALIVE:
                v.val = sock_flag(sk, SOCK_KEEPOPEN);
                break;
@@ -1140,6 +1154,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 
                goto lenout;
 
+       case SO_LOCK_FILTER:
+               v.val = sock_flag(sk, SOCK_FILTER_LOCKED);
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
index d1b08045a9dfbf4dbee4255c68cdcd6ad1e026a2..cfdb46ab3a7f866dd77957abc2f202d673c99bd5 100644 (file)
@@ -20,6 +20,8 @@
 #include <net/sock.h>
 #include <net/net_ratelimit.h>
 
+static int one = 1;
+
 #ifdef CONFIG_RPS
 static int rps_sock_flow_sysctl(ctl_table *table, int write,
                                void __user *buffer, size_t *lenp, loff_t *ppos)
@@ -92,28 +94,32 @@ static struct ctl_table net_core_table[] = {
                .data           = &sysctl_wmem_max,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
        },
        {
                .procname       = "rmem_max",
                .data           = &sysctl_rmem_max,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
        },
        {
                .procname       = "wmem_default",
                .data           = &sysctl_wmem_default,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
        },
        {
                .procname       = "rmem_default",
                .data           = &sysctl_rmem_default,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
        },
        {
                .procname       = "dev_weight",
index 307c322d53bb889540aa3d302a69b13646f0cda3..64d9843f9e048a0eae31157b392fb09fd74d2ecf 100644 (file)
@@ -909,6 +909,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen,
        struct dn_scp *scp = DN_SK(sk);
        int err = -EISCONN;
        struct flowidn fld;
+       struct dst_entry *dst;
 
        if (sock->state == SS_CONNECTED)
                goto out;
@@ -955,10 +956,11 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen,
        fld.flowidn_proto = DNPROTO_NSP;
        if (dn_route_output_sock(&sk->sk_dst_cache, &fld, sk, flags) < 0)
                goto out;
-       sk->sk_route_caps = sk->sk_dst_cache->dev->features;
+       dst = __sk_dst_get(sk);
+       sk->sk_route_caps = dst->dev->features;
        sock->state = SS_CONNECTING;
        scp->state = DN_CI;
-       scp->segsize_loc = dst_metric_advmss(sk->sk_dst_cache);
+       scp->segsize_loc = dst_metric_advmss(dst);
 
        dn_nsp_send_conninit(sk, NSP_CI);
        err = -EINPROGRESS;
index 8a96047c7c94334a217d9f85a7b091545e1e95d0..1aaa51ebbda6ed1271b2a44820860f4d338b2f66 100644 (file)
@@ -598,7 +598,7 @@ void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg,
        if (reason == 0)
                reason = le16_to_cpu(scp->discdata_out.opt_status);
 
-       dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl,
+       dn_nsp_do_disc(sk, msgflg, reason, gfp, __sk_dst_get(sk), ddl,
                scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
 }
 
index b57419cc41a486b3ab2ddc82643169c97b19d132..1550028fcd8ef7803c942d2a5e246fd0ac445297 100644 (file)
@@ -1282,7 +1282,7 @@ static int dn_route_output_key(struct dst_entry **pprt, struct flowidn *flp, int
        return err;
 }
 
-int dn_route_output_sock(struct dst_entry **pprt, struct flowidn *fl, struct sock *sk, int flags)
+int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *fl, struct sock *sk, int flags)
 {
        int err;
 
index 45295ca095717314294e1be8172a6e852fe1a679..2bc62ea857c8b6842c27ed9d6ee12b564fb2d1e6 100644 (file)
@@ -80,6 +80,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
        int ret;
        char *name;
        int i;
+       bool valid_name_found = false;
 
        /*
         * Probe for switch model.
@@ -131,8 +132,13 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
                } else {
                        ds->phys_port_mask |= 1 << i;
                }
+               valid_name_found = true;
        }
 
+       if (!valid_name_found && i == DSA_MAX_PORTS) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /*
         * If the CPU connects to this switch, set the switch tree
index e32083d5d8f8370d363b58b8c461cac53ce983ed..6ebd8fbd92855763013b5feefbb8123e0ee7fe3e 100644 (file)
@@ -41,8 +41,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
        ds->slave_mii_bus->name = "dsa slave smi";
        ds->slave_mii_bus->read = dsa_slave_phy_read;
        ds->slave_mii_bus->write = dsa_slave_phy_write;
-       snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x",
-                       ds->master_mii_bus->id, ds->pd->sw_addr);
+       snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d:%.2x",
+                       ds->index, ds->pd->sw_addr);
        ds->slave_mii_bus->parent = &ds->master_mii_bus->dev;
 }
 
@@ -203,10 +203,10 @@ dsa_slave_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void dsa_slave_get_drvinfo(struct net_device *dev,
                                  struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver, "dsa", 32);
-       strncpy(drvinfo->version, dsa_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, "platform", 32);
+       strlcpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, dsa_driver_version, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info));
 }
 
 static int dsa_slave_nway_reset(struct net_device *dev)
@@ -391,7 +391,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 
        if (p->phy != NULL) {
                phy_attach(slave_dev, dev_name(&p->phy->dev),
-                          0, PHY_INTERFACE_MODE_GMII);
+                          PHY_INTERFACE_MODE_GMII);
 
                p->phy->autoneg = AUTONEG_ENABLE;
                p->phy->speed = 0;
index 4efad533e5f68bec0dc2224cd3952371018445f1..a36c85eab5b4ebf9992794f3822fd8553f7458c9 100644 (file)
@@ -271,6 +271,36 @@ void eth_header_cache_update(struct hh_cache *hh,
 }
 EXPORT_SYMBOL(eth_header_cache_update);
 
+/**
+ * eth_prepare_mac_addr_change - prepare for mac change
+ * @dev: network device
+ * @p: socket address
+ */
+int eth_prepare_mac_addr_change(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+
+       if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev))
+               return -EBUSY;
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+       return 0;
+}
+EXPORT_SYMBOL(eth_prepare_mac_addr_change);
+
+/**
+ * eth_commit_mac_addr_change - commit mac change
+ * @dev: network device
+ * @p: socket address
+ */
+void eth_commit_mac_addr_change(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+}
+EXPORT_SYMBOL(eth_commit_mac_addr_change);
+
 /**
  * eth_mac_addr - set new Ethernet hardware address
  * @dev: network device
@@ -283,15 +313,12 @@ EXPORT_SYMBOL(eth_header_cache_update);
  */
 int eth_mac_addr(struct net_device *dev, void *p)
 {
-       struct sockaddr *addr = p;
+       int ret;
 
-       if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev))
-               return -EBUSY;
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
-       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
-       /* if device marked as NET_ADDR_RANDOM, reset it */
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
+       ret = eth_prepare_mac_addr_change(dev, p);
+       if (ret < 0)
+               return ret;
+       eth_commit_mac_addr_change(dev, p);
        return 0;
 }
 EXPORT_SYMBOL(eth_mac_addr);
index f651da60f1618f089c2d21eef069ac5b3648218d..09cba81d2c4ab65f18963a34f9a7857fc4860367 100644 (file)
@@ -594,10 +594,32 @@ static int lowpan_header_create(struct sk_buff *skb,
        }
 }
 
+static int lowpan_give_skb_to_devices(struct sk_buff *skb)
+{
+       struct lowpan_dev_record *entry;
+       struct sk_buff *skb_cp;
+       int stat = NET_RX_SUCCESS;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(entry, &lowpan_devices, list)
+               if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
+                       skb_cp = skb_copy(skb, GFP_ATOMIC);
+                       if (!skb_cp) {
+                               stat = -ENOMEM;
+                               break;
+                       }
+
+                       skb_cp->dev = entry->ldev;
+                       stat = netif_rx(skb_cp);
+               }
+       rcu_read_unlock();
+
+       return stat;
+}
+
 static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
 {
        struct sk_buff *new;
-       struct lowpan_dev_record *entry;
        int stat = NET_RX_SUCCESS;
 
        new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
@@ -614,19 +636,7 @@ static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
        new->protocol = htons(ETH_P_IPV6);
        new->pkt_type = PACKET_HOST;
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(entry, &lowpan_devices, list)
-               if (lowpan_dev_info(entry->ldev)->real_dev == new->dev) {
-                       skb = skb_copy(new, GFP_ATOMIC);
-                       if (!skb) {
-                               stat = -ENOMEM;
-                               break;
-                       }
-
-                       skb->dev = entry->ldev;
-                       stat = netif_rx(skb);
-               }
-       rcu_read_unlock();
+       stat = lowpan_give_skb_to_devices(new);
 
        kfree_skb(new);
 
@@ -1137,19 +1147,42 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                goto drop;
 
        /* check that it's our buffer */
-       switch (skb->data[0] & 0xe0) {
-       case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
-       case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
-       case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
-               local_skb = skb_clone(skb, GFP_ATOMIC);
+       if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
+               /* Copy the packet so that the IPv6 header is
+                * properly aligned.
+                */
+               local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
+                                           skb_tailroom(skb), GFP_ATOMIC);
                if (!local_skb)
                        goto drop;
-               lowpan_process_data(local_skb);
 
+               local_skb->protocol = htons(ETH_P_IPV6);
+               local_skb->pkt_type = PACKET_HOST;
+
+               /* Pull off the 1-byte of 6lowpan header. */
+               skb_pull(local_skb, 1);
+               skb_reset_network_header(local_skb);
+               skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
+
+               lowpan_give_skb_to_devices(local_skb);
+
+               kfree_skb(local_skb);
                kfree_skb(skb);
-               break;
-       default:
-               break;
+       } else {
+               switch (skb->data[0] & 0xe0) {
+               case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
+               case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
+               case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
+                       local_skb = skb_clone(skb, GFP_ATOMIC);
+                       if (!local_skb)
+                               goto drop;
+                       lowpan_process_data(local_skb);
+
+                       kfree_skb(skb);
+                       break;
+               default:
+                       break;
+               }
        }
 
        return NET_RX_SUCCESS;
index 24b384b7903ea7a59a11e7a4cbf06db996498924..49ddca31c4daf4ac50923d540901b99f33a29f0e 100644 (file)
@@ -1306,6 +1306,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
                       SKB_GSO_UDP |
                       SKB_GSO_DODGY |
                       SKB_GSO_TCP_ECN |
+                      SKB_GSO_SHARED_FRAG |
                       0)))
                goto out;
 
@@ -1333,7 +1334,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
                segs = ops->callbacks.gso_segment(skb, features);
        rcu_read_unlock();
 
-       if (!segs || IS_ERR(segs))
+       if (IS_ERR_OR_NULL(segs))
                goto out;
 
        skb = segs;
@@ -1705,12 +1706,11 @@ static struct packet_type ip_packet_type __read_mostly = {
 
 static int __init inet_init(void)
 {
-       struct sk_buff *dummy_skb;
        struct inet_protosw *q;
        struct list_head *r;
        int rc = -EINVAL;
 
-       BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));
+       BUILD_BUG_ON(sizeof(struct inet_skb_parm) > FIELD_SIZEOF(struct sk_buff, cb));
 
        sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);
        if (!sysctl_local_reserved_ports)
index a8e4f2665d5e6687c28438de69586673be9b3484..5281314886c1fc3d0bb0488b9338a5a2124158e9 100644 (file)
@@ -63,6 +63,7 @@
 #include <net/ip_fib.h>
 #include <net/rtnetlink.h>
 #include <net/net_namespace.h>
+#include <net/addrconf.h>
 
 #include "fib_lookup.h"
 
@@ -93,6 +94,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
        [IFA_ADDRESS]           = { .type = NLA_U32 },
        [IFA_BROADCAST]         = { .type = NLA_U32 },
        [IFA_LABEL]             = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
+       [IFA_CACHEINFO]         = { .len = sizeof(struct ifa_cacheinfo) },
 };
 
 #define IN4_ADDR_HSIZE_SHIFT   8
@@ -417,6 +419,10 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
        __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
 }
 
+static void check_lifetime(struct work_struct *work);
+
+static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
+
 static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
                             u32 portid)
 {
@@ -462,6 +468,9 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
 
        inet_hash_insert(dev_net(in_dev->dev), ifa);
 
+       cancel_delayed_work(&check_lifetime_work);
+       schedule_delayed_work(&check_lifetime_work, 0);
+
        /* Send message first, then call notifier.
           Notifier will trigger FIB update, so that
           listeners of netlink will know about new ifaddr */
@@ -573,7 +582,107 @@ errout:
        return err;
 }
 
-static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
+#define INFINITY_LIFE_TIME     0xFFFFFFFF
+
+static void check_lifetime(struct work_struct *work)
+{
+       unsigned long now, next, next_sec, next_sched;
+       struct in_ifaddr *ifa;
+       struct hlist_node *node;
+       int i;
+
+       now = jiffies;
+       next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
+
+       rcu_read_lock();
+       for (i = 0; i < IN4_ADDR_HSIZE; i++) {
+               hlist_for_each_entry_rcu(ifa, node,
+                                        &inet_addr_lst[i], hash) {
+                       unsigned long age;
+
+                       if (ifa->ifa_flags & IFA_F_PERMANENT)
+                               continue;
+
+                       /* We try to batch several events at once. */
+                       age = (now - ifa->ifa_tstamp +
+                              ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+
+                       if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
+                           age >= ifa->ifa_valid_lft) {
+                               struct in_ifaddr **ifap ;
+
+                               rtnl_lock();
+                               for (ifap = &ifa->ifa_dev->ifa_list;
+                                    *ifap != NULL; ifap = &ifa->ifa_next) {
+                                       if (*ifap == ifa)
+                                               inet_del_ifa(ifa->ifa_dev,
+                                                            ifap, 1);
+                               }
+                               rtnl_unlock();
+                       } else if (ifa->ifa_preferred_lft ==
+                                  INFINITY_LIFE_TIME) {
+                               continue;
+                       } else if (age >= ifa->ifa_preferred_lft) {
+                               if (time_before(ifa->ifa_tstamp +
+                                               ifa->ifa_valid_lft * HZ, next))
+                                       next = ifa->ifa_tstamp +
+                                              ifa->ifa_valid_lft * HZ;
+
+                               if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) {
+                                       ifa->ifa_flags |= IFA_F_DEPRECATED;
+                                       rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
+                               }
+                       } else if (time_before(ifa->ifa_tstamp +
+                                              ifa->ifa_preferred_lft * HZ,
+                                              next)) {
+                               next = ifa->ifa_tstamp +
+                                      ifa->ifa_preferred_lft * HZ;
+                       }
+               }
+       }
+       rcu_read_unlock();
+
+       next_sec = round_jiffies_up(next);
+       next_sched = next;
+
+       /* If rounded timeout is accurate enough, accept it. */
+       if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
+               next_sched = next_sec;
+
+       now = jiffies;
+       /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
+       if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
+               next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
+
+       schedule_delayed_work(&check_lifetime_work, next_sched - now);
+}
+
+static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
+                            __u32 prefered_lft)
+{
+       unsigned long timeout;
+
+       ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
+
+       timeout = addrconf_timeout_fixup(valid_lft, HZ);
+       if (addrconf_finite_timeout(timeout))
+               ifa->ifa_valid_lft = timeout;
+       else
+               ifa->ifa_flags |= IFA_F_PERMANENT;
+
+       timeout = addrconf_timeout_fixup(prefered_lft, HZ);
+       if (addrconf_finite_timeout(timeout)) {
+               if (timeout == 0)
+                       ifa->ifa_flags |= IFA_F_DEPRECATED;
+               ifa->ifa_preferred_lft = timeout;
+       }
+       ifa->ifa_tstamp = jiffies;
+       if (!ifa->ifa_cstamp)
+               ifa->ifa_cstamp = ifa->ifa_tstamp;
+}
+
+static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
+                                      __u32 *pvalid_lft, __u32 *pprefered_lft)
 {
        struct nlattr *tb[IFA_MAX+1];
        struct in_ifaddr *ifa;
@@ -633,24 +742,73 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
        else
                memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 
+       if (tb[IFA_CACHEINFO]) {
+               struct ifa_cacheinfo *ci;
+
+               ci = nla_data(tb[IFA_CACHEINFO]);
+               if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
+                       err = -EINVAL;
+                       goto errout;
+               }
+               *pvalid_lft = ci->ifa_valid;
+               *pprefered_lft = ci->ifa_prefered;
+       }
+
        return ifa;
 
 errout:
        return ERR_PTR(err);
 }
 
+static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
+{
+       struct in_device *in_dev = ifa->ifa_dev;
+       struct in_ifaddr *ifa1, **ifap;
+
+       if (!ifa->ifa_local)
+               return NULL;
+
+       for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
+            ifap = &ifa1->ifa_next) {
+               if (ifa1->ifa_mask == ifa->ifa_mask &&
+                   inet_ifa_match(ifa1->ifa_address, ifa) &&
+                   ifa1->ifa_local == ifa->ifa_local)
+                       return ifa1;
+       }
+       return NULL;
+}
+
 static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct net *net = sock_net(skb->sk);
        struct in_ifaddr *ifa;
+       struct in_ifaddr *ifa_existing;
+       __u32 valid_lft = INFINITY_LIFE_TIME;
+       __u32 prefered_lft = INFINITY_LIFE_TIME;
 
        ASSERT_RTNL();
 
-       ifa = rtm_to_ifaddr(net, nlh);
+       ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
        if (IS_ERR(ifa))
                return PTR_ERR(ifa);
 
-       return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
+       ifa_existing = find_matching_ifa(ifa);
+       if (!ifa_existing) {
+               /* It would be best to check for !NLM_F_CREATE here but
+                * userspace alreay relies on not having to provide this.
+                */
+               set_ifa_lifetime(ifa, valid_lft, prefered_lft);
+               return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
+       } else {
+               inet_free_ifa(ifa);
+
+               if (nlh->nlmsg_flags & NLM_F_EXCL ||
+                   !(nlh->nlmsg_flags & NLM_F_REPLACE))
+                       return -EEXIST;
+
+               set_ifa_lifetime(ifa_existing, valid_lft, prefered_lft);
+       }
+       return 0;
 }
 
 /*
@@ -852,6 +1010,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                        ifa->ifa_prefixlen = 32;
                        ifa->ifa_mask = inet_make_mask(32);
                }
+               set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
                ret = inet_set_ifa(dev, ifa);
                break;
 
@@ -1190,6 +1349,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
                                ifa->ifa_dev = in_dev;
                                ifa->ifa_scope = RT_SCOPE_HOST;
                                memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+                               set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
+                                                INFINITY_LIFE_TIME);
                                inet_insert_ifa(ifa);
                        }
                }
@@ -1246,11 +1407,30 @@ static size_t inet_nlmsg_size(void)
               + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
 }
 
+static inline u32 cstamp_delta(unsigned long cstamp)
+{
+       return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
+}
+
+static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
+                        unsigned long tstamp, u32 preferred, u32 valid)
+{
+       struct ifa_cacheinfo ci;
+
+       ci.cstamp = cstamp_delta(cstamp);
+       ci.tstamp = cstamp_delta(tstamp);
+       ci.ifa_prefered = preferred;
+       ci.ifa_valid = valid;
+
+       return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
+}
+
 static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
                            u32 portid, u32 seq, int event, unsigned int flags)
 {
        struct ifaddrmsg *ifm;
        struct nlmsghdr  *nlh;
+       u32 preferred, valid;
 
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
        if (nlh == NULL)
@@ -1259,10 +1439,31 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
        ifm = nlmsg_data(nlh);
        ifm->ifa_family = AF_INET;
        ifm->ifa_prefixlen = ifa->ifa_prefixlen;
-       ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
+       ifm->ifa_flags = ifa->ifa_flags;
        ifm->ifa_scope = ifa->ifa_scope;
        ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
 
+       if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
+               preferred = ifa->ifa_preferred_lft;
+               valid = ifa->ifa_valid_lft;
+               if (preferred != INFINITY_LIFE_TIME) {
+                       long tval = (jiffies - ifa->ifa_tstamp) / HZ;
+
+                       if (preferred > tval)
+                               preferred -= tval;
+                       else
+                               preferred = 0;
+                       if (valid != INFINITY_LIFE_TIME) {
+                               if (valid > tval)
+                                       valid -= tval;
+                               else
+                                       valid = 0;
+                       }
+               }
+       } else {
+               preferred = INFINITY_LIFE_TIME;
+               valid = INFINITY_LIFE_TIME;
+       }
        if ((ifa->ifa_address &&
             nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
            (ifa->ifa_local &&
@@ -1270,7 +1471,9 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
            (ifa->ifa_broadcast &&
             nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
            (ifa->ifa_label[0] &&
-            nla_put_string(skb, IFA_LABEL, ifa->ifa_label)))
+            nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
+           put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
+                         preferred, valid))
                goto nla_put_failure;
 
        return nlmsg_end(skb, nlh);
@@ -1988,6 +2191,8 @@ void __init devinet_init(void)
        register_gifconf(PF_INET, inet_gifconf);
        register_netdevice_notifier(&ip_netdev_notifier);
 
+       schedule_delayed_work(&check_lifetime_work, 0);
+
        rtnl_af_register(&inet_af_ops);
 
        rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);
index 5cd75e2dab2c17377d7250680c6b32717fe9cce9..99f00d39d10b7a9873ba565c45a485620c418c83 100644 (file)
@@ -974,7 +974,7 @@ static void nl_fib_input(struct sk_buff *skb)
 
        nl_fib_lookup(frn, tb);
 
-       portid = NETLINK_CB(skb).portid;      /* pid of sending process */
+       portid = NETLINK_CB(skb).portid;      /* netlink portid */
        NETLINK_CB(skb).portid = 0;        /* from kernel */
        NETLINK_CB(skb).dst_group = 0;  /* unicast */
        netlink_unicast(net->ipv4.fibnl, skb, portid, MSG_DONTWAIT);
index d0670f00d5243f95bec4536f60edf32fa2ded850..11cb4979a465af4c037ea60b6852870c2e7f725e 100644 (file)
@@ -59,6 +59,8 @@ int inet_csk_bind_conflict(const struct sock *sk,
        struct sock *sk2;
        struct hlist_node *node;
        int reuse = sk->sk_reuse;
+       int reuseport = sk->sk_reuseport;
+       kuid_t uid = sock_i_uid((struct sock *)sk);
 
        /*
         * Unlike other sk lookup places we do not check
@@ -73,8 +75,11 @@ int inet_csk_bind_conflict(const struct sock *sk,
                    (!sk->sk_bound_dev_if ||
                     !sk2->sk_bound_dev_if ||
                     sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
-                       if (!reuse || !sk2->sk_reuse ||
-                           sk2->sk_state == TCP_LISTEN) {
+                       if ((!reuse || !sk2->sk_reuse ||
+                           sk2->sk_state == TCP_LISTEN) &&
+                           (!reuseport || !sk2->sk_reuseport ||
+                           (sk2->sk_state != TCP_TIME_WAIT &&
+                            !uid_eq(uid, sock_i_uid(sk2))))) {
                                const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
                                if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) ||
                                    sk2_rcv_saddr == sk_rcv_saddr(sk))
@@ -106,6 +111,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
        int ret, attempts = 5;
        struct net *net = sock_net(sk);
        int smallest_size = -1, smallest_rover;
+       kuid_t uid = sock_i_uid(sk);
 
        local_bh_disable();
        if (!snum) {
@@ -125,9 +131,12 @@ again:
                        spin_lock(&head->lock);
                        inet_bind_bucket_for_each(tb, node, &head->chain)
                                if (net_eq(ib_net(tb), net) && tb->port == rover) {
-                                       if (tb->fastreuse > 0 &&
-                                           sk->sk_reuse &&
-                                           sk->sk_state != TCP_LISTEN &&
+                                       if (((tb->fastreuse > 0 &&
+                                             sk->sk_reuse &&
+                                             sk->sk_state != TCP_LISTEN) ||
+                                            (tb->fastreuseport > 0 &&
+                                             sk->sk_reuseport &&
+                                             uid_eq(tb->fastuid, uid))) &&
                                            (tb->num_owners < smallest_size || smallest_size == -1)) {
                                                smallest_size = tb->num_owners;
                                                smallest_rover = rover;
@@ -185,14 +194,18 @@ tb_found:
                if (sk->sk_reuse == SK_FORCE_REUSE)
                        goto success;
 
-               if (tb->fastreuse > 0 &&
-                   sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
+               if (((tb->fastreuse > 0 &&
+                     sk->sk_reuse && sk->sk_state != TCP_LISTEN) ||
+                    (tb->fastreuseport > 0 &&
+                     sk->sk_reuseport && uid_eq(tb->fastuid, uid))) &&
                    smallest_size == -1) {
                        goto success;
                } else {
                        ret = 1;
                        if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, true)) {
-                               if (sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
+                               if (((sk->sk_reuse && sk->sk_state != TCP_LISTEN) ||
+                                    (tb->fastreuseport > 0 &&
+                                     sk->sk_reuseport && uid_eq(tb->fastuid, uid))) &&
                                    smallest_size != -1 && --attempts >= 0) {
                                        spin_unlock(&head->lock);
                                        goto again;
@@ -212,9 +225,19 @@ tb_not_found:
                        tb->fastreuse = 1;
                else
                        tb->fastreuse = 0;
-       } else if (tb->fastreuse &&
-                  (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
-               tb->fastreuse = 0;
+               if (sk->sk_reuseport) {
+                       tb->fastreuseport = 1;
+                       tb->fastuid = uid;
+               } else
+                       tb->fastreuseport = 0;
+       } else {
+               if (tb->fastreuse &&
+                   (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
+                       tb->fastreuse = 0;
+               if (tb->fastreuseport &&
+                   (!sk->sk_reuseport || !uid_eq(tb->fastuid, uid)))
+                       tb->fastreuseport = 0;
+       }
 success:
        if (!inet_csk(sk)->icsk_bind_hash)
                inet_bind_hash(sk, tb, snum);
index 4750d2b74d79324cdc3176b7a9cbbe0d13c4e9c7..2e453bde69922dfd204d99d0fe2f1cf561149269 100644 (file)
@@ -73,8 +73,9 @@ EXPORT_SYMBOL(inet_frags_init);
 void inet_frags_init_net(struct netns_frags *nf)
 {
        nf->nqueues = 0;
-       atomic_set(&nf->mem, 0);
+       init_frag_mem_limit(nf);
        INIT_LIST_HEAD(&nf->lru_list);
+       spin_lock_init(&nf->lru_lock);
 }
 EXPORT_SYMBOL(inet_frags_init_net);
 
@@ -91,6 +92,8 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f)
        local_bh_disable();
        inet_frag_evictor(nf, f, true);
        local_bh_enable();
+
+       percpu_counter_destroy(&nf->mem);
 }
 EXPORT_SYMBOL(inet_frags_exit_net);
 
@@ -98,9 +101,9 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
 {
        write_lock(&f->lock);
        hlist_del(&fq->list);
-       list_del(&fq->lru_list);
        fq->net->nqueues--;
        write_unlock(&f->lock);
+       inet_frag_lru_del(fq);
 }
 
 void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
@@ -117,12 +120,8 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
 EXPORT_SYMBOL(inet_frag_kill);
 
 static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f,
-               struct sk_buff *skb, int *work)
+               struct sk_buff *skb)
 {
-       if (work)
-               *work -= skb->truesize;
-
-       atomic_sub(skb->truesize, &nf->mem);
        if (f->skb_free)
                f->skb_free(skb);
        kfree_skb(skb);
@@ -133,6 +132,7 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
 {
        struct sk_buff *fp;
        struct netns_frags *nf;
+       unsigned int sum, sum_truesize = 0;
 
        WARN_ON(!(q->last_in & INET_FRAG_COMPLETE));
        WARN_ON(del_timer(&q->timer) != 0);
@@ -143,13 +143,14 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
        while (fp) {
                struct sk_buff *xp = fp->next;
 
-               frag_kfree_skb(nf, f, fp, work);
+               sum_truesize += fp->truesize;
+               frag_kfree_skb(nf, f, fp);
                fp = xp;
        }
-
+       sum = sum_truesize + f->qsize;
        if (work)
-               *work -= f->qsize;
-       atomic_sub(f->qsize, &nf->mem);
+               *work -= sum;
+       sub_frag_mem_limit(q, sum);
 
        if (f->destructor)
                f->destructor(q);
@@ -164,22 +165,23 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
        int work, evicted = 0;
 
        if (!force) {
-               if (atomic_read(&nf->mem) <= nf->high_thresh)
+               if (frag_mem_limit(nf) <= nf->high_thresh)
                        return 0;
        }
 
-       work = atomic_read(&nf->mem) - nf->low_thresh;
+       work = frag_mem_limit(nf) - nf->low_thresh;
        while (work > 0) {
-               read_lock(&f->lock);
+               spin_lock(&nf->lru_lock);
+
                if (list_empty(&nf->lru_list)) {
-                       read_unlock(&f->lock);
+                       spin_unlock(&nf->lru_lock);
                        break;
                }
 
                q = list_first_entry(&nf->lru_list,
                                struct inet_frag_queue, lru_list);
                atomic_inc(&q->refcnt);
-               read_unlock(&f->lock);
+               spin_unlock(&nf->lru_lock);
 
                spin_lock(&q->lock);
                if (!(q->last_in & INET_FRAG_COMPLETE))
@@ -233,9 +235,9 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
 
        atomic_inc(&qp->refcnt);
        hlist_add_head(&qp->list, &f->hash[hash]);
-       list_add_tail(&qp->lru_list, &nf->lru_list);
        nf->nqueues++;
        write_unlock(&f->lock);
+       inet_frag_lru_add(nf, qp);
        return qp;
 }
 
@@ -250,7 +252,8 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
 
        q->net = nf;
        f->constructor(q, arg);
-       atomic_add(f->qsize, &nf->mem);
+       add_frag_mem_limit(q, f->qsize);
+
        setup_timer(&q->timer, f->frag_expire, (unsigned long)q);
        spin_lock_init(&q->lock);
        atomic_set(&q->refcnt, 1);
index fa3ae814871082e22121855a4033ddc4ec21b1c7..0ce0595d98618492ce17c285aadba6076dcec9ce 100644 (file)
@@ -39,6 +39,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
                write_pnet(&tb->ib_net, hold_net(net));
                tb->port      = snum;
                tb->fastreuse = 0;
+               tb->fastreuseport = 0;
                tb->num_owners = 0;
                INIT_HLIST_HEAD(&tb->owners);
                hlist_add_head(&tb->node, &head->chain);
@@ -151,16 +152,16 @@ static inline int compute_score(struct sock *sk, struct net *net,
        if (net_eq(sock_net(sk), net) && inet->inet_num == hnum &&
                        !ipv6_only_sock(sk)) {
                __be32 rcv_saddr = inet->inet_rcv_saddr;
-               score = sk->sk_family == PF_INET ? 1 : 0;
+               score = sk->sk_family == PF_INET ? 2 : 1;
                if (rcv_saddr) {
                        if (rcv_saddr != daddr)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
                if (sk->sk_bound_dev_if) {
                        if (sk->sk_bound_dev_if != dif)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
        }
        return score;
@@ -176,6 +177,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
 
 struct sock *__inet_lookup_listener(struct net *net,
                                    struct inet_hashinfo *hashinfo,
+                                   const __be32 saddr, __be16 sport,
                                    const __be32 daddr, const unsigned short hnum,
                                    const int dif)
 {
@@ -183,17 +185,29 @@ struct sock *__inet_lookup_listener(struct net *net,
        struct hlist_nulls_node *node;
        unsigned int hash = inet_lhashfn(net, hnum);
        struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
-       int score, hiscore;
+       int score, hiscore, matches = 0, reuseport = 0;
+       u32 phash = 0;
 
        rcu_read_lock();
 begin:
        result = NULL;
-       hiscore = -1;
+       hiscore = 0;
        sk_nulls_for_each_rcu(sk, node, &ilb->head) {
                score = compute_score(sk, net, hnum, daddr, dif);
                if (score > hiscore) {
                        result = sk;
                        hiscore = score;
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               phash = inet_ehashfn(net, daddr, hnum,
+                                                    saddr, sport);
+                               matches = 1;
+                       }
+               } else if (score == hiscore && reuseport) {
+                       matches++;
+                       if (((u64)phash * matches) >> 32 == 0)
+                               result = sk;
+                       phash = next_pseudo_random32(phash);
                }
        }
        /*
@@ -501,7 +515,8 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
                        inet_bind_bucket_for_each(tb, node, &head->chain) {
                                if (net_eq(ib_net(tb), net) &&
                                    tb->port == port) {
-                                       if (tb->fastreuse >= 0)
+                                       if (tb->fastreuse >= 0 ||
+                                           tb->fastreuseport >= 0)
                                                goto next_port;
                                        WARN_ON(hlist_empty(&tb->owners));
                                        if (!check_established(death_row, sk,
@@ -518,6 +533,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
                                break;
                        }
                        tb->fastreuse = -1;
+                       tb->fastreuseport = -1;
                        goto ok;
 
                next_port:
index eb9d63a570cd1ce595076096d9b2aea3723a4c38..1211613c6c3401f520e8eb2209435e4b71360684 100644 (file)
@@ -122,7 +122,7 @@ int ip_frag_nqueues(struct net *net)
 
 int ip_frag_mem(struct net *net)
 {
-       return atomic_read(&net->ipv4.frags.mem);
+       return sum_frag_mem_limit(&net->ipv4.frags);
 }
 
 static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
@@ -161,13 +161,6 @@ static bool ip4_frag_match(struct inet_frag_queue *q, void *a)
                qp->user == arg->user;
 }
 
-/* Memory Tracking Functions. */
-static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
-{
-       atomic_sub(skb->truesize, &nf->mem);
-       kfree_skb(skb);
-}
-
 static void ip4_frag_init(struct inet_frag_queue *q, void *a)
 {
        struct ipq *qp = container_of(q, struct ipq, q);
@@ -340,6 +333,7 @@ static inline int ip_frag_too_far(struct ipq *qp)
 static int ip_frag_reinit(struct ipq *qp)
 {
        struct sk_buff *fp;
+       unsigned int sum_truesize = 0;
 
        if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) {
                atomic_inc(&qp->q.refcnt);
@@ -349,9 +343,12 @@ static int ip_frag_reinit(struct ipq *qp)
        fp = qp->q.fragments;
        do {
                struct sk_buff *xp = fp->next;
-               frag_kfree_skb(qp->q.net, fp);
+
+               sum_truesize += fp->truesize;
+               kfree_skb(fp);
                fp = xp;
        } while (fp);
+       sub_frag_mem_limit(&qp->q, sum_truesize);
 
        qp->q.last_in = 0;
        qp->q.len = 0;
@@ -496,7 +493,8 @@ found:
                                qp->q.fragments = next;
 
                        qp->q.meat -= free_it->len;
-                       frag_kfree_skb(qp->q.net, free_it);
+                       sub_frag_mem_limit(&qp->q, free_it->truesize);
+                       kfree_skb(free_it);
                }
        }
 
@@ -519,7 +517,7 @@ found:
        qp->q.stamp = skb->tstamp;
        qp->q.meat += skb->len;
        qp->ecn |= ecn;
-       atomic_add(skb->truesize, &qp->q.net->mem);
+       add_frag_mem_limit(&qp->q, skb->truesize);
        if (offset == 0)
                qp->q.last_in |= INET_FRAG_FIRST_IN;
 
@@ -531,9 +529,7 @@ found:
            qp->q.meat == qp->q.len)
                return ip_frag_reasm(qp, prev, dev);
 
-       write_lock(&ip4_frags.lock);
-       list_move_tail(&qp->q.lru_list, &qp->q.net->lru_list);
-       write_unlock(&ip4_frags.lock);
+       inet_frag_lru_move(&qp->q);
        return -EINPROGRESS;
 
 err:
@@ -617,7 +613,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               atomic_add(clone->truesize, &qp->q.net->mem);
+               add_frag_mem_limit(&qp->q, clone->truesize);
        }
 
        skb_push(head, head->data - skb_network_header(head));
@@ -645,7 +641,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                }
                fp = next;
        }
-       atomic_sub(sum_truesize, &qp->q.net->mem);
+       sub_frag_mem_limit(&qp->q, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
@@ -851,14 +847,22 @@ static inline void ip4_frags_ctl_register(void)
 
 static int __net_init ipv4_frags_init_net(struct net *net)
 {
-       /*
-        * Fragment cache limits. We will commit 256K at one time. Should we
-        * cross that limit we will prune down to 192K. This should cope with
-        * even the most extreme cases without allowing an attacker to
-        * measurably harm machine performance.
+       /* Fragment cache limits.
+        *
+        * The fragment memory accounting code, (tries to) account for
+        * the real memory usage, by measuring both the size of frag
+        * queue struct (inet_frag_queue (ipv4:ipq/ipv6:frag_queue))
+        * and the SKB's truesize.
+        *
+        * A 64K fragment consumes 129736 bytes (44*2944)+200
+        * (1500 truesize == 2944, sizeof(struct ipq) == 200)
+        *
+        * We will commit 4MB at one time. Should we cross that limit
+        * we will prune down to 3MB, making room for approx 8 big 64K
+        * fragments 8x128k.
         */
-       net->ipv4.frags.high_thresh = 256 * 1024;
-       net->ipv4.frags.low_thresh = 192 * 1024;
+       net->ipv4.frags.high_thresh = 4 * 1024 * 1024;
+       net->ipv4.frags.low_thresh  = 3 * 1024 * 1024;
        /*
         * Important NOTE! Fragment queue must be destroyed before MSL expires.
         * RFC791 is wrong proposing to prolongate timer each fragment arrival
index e81b1caf2ea2a0ceaa20ef8e1847ebd4f71cd98e..00a14b9864ea91b3d87955efa06c45d1ffe64d10 100644 (file)
@@ -738,7 +738,7 @@ drop:
 static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       const struct iphdr  *old_iph = ip_hdr(skb);
+       const struct iphdr  *old_iph;
        const struct iphdr  *tiph;
        struct flowi4 fl4;
        u8     tos;
@@ -756,6 +756,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
            skb_checksum_help(skb))
                goto tx_error;
 
+       old_iph = ip_hdr(skb);
+
        if (dev->type == ARPHRD_ETHER)
                IPCB(skb)->flags = 0;
 
@@ -818,8 +820,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
 
        ttl = tiph->ttl;
        tos = tiph->tos;
-       if (tos == 1) {
-               tos = 0;
+       if (tos & 0x1) {
+               tos &= ~0x1;
                if (skb->protocol == htons(ETH_P_IP))
                        tos = old_iph->tos;
                else if (skb->protocol == htons(ETH_P_IPV6))
index 191fc24a745a9668332f74106fd39831d9f01c53..8f024d41eefa9d828af4969b84134e8c94087ffd 100644 (file)
@@ -472,7 +472,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        __be16 df = tiph->frag_off;
        struct rtable *rt;                      /* Route to the other host */
        struct net_device *tdev;                /* Device to other host */
-       const struct iphdr  *old_iph = ip_hdr(skb);
+       const struct iphdr  *old_iph;
        struct iphdr  *iph;                     /* Our new IP header */
        unsigned int max_headroom;              /* The extra header space needed */
        __be32 dst = tiph->daddr;
@@ -486,6 +486,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
            skb_checksum_help(skb))
                goto tx_error;
 
+       old_iph = ip_hdr(skb);
+
        if (tos & 1)
                tos = old_iph->tos;
 
index a9454cbd953ce700139fdb010a333128b565b800..7085b9b51e7f9eba5fd249ee8b5ec92096f10ca5 100644 (file)
@@ -828,6 +828,49 @@ static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
        return NULL;
 }
 
+/* Look for a (*,*,oif) entry */
+static struct mfc_cache *ipmr_cache_find_any_parent(struct mr_table *mrt,
+                                                   int vifi)
+{
+       int line = MFC_HASH(htonl(INADDR_ANY), htonl(INADDR_ANY));
+       struct mfc_cache *c;
+
+       list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
+               if (c->mfc_origin == htonl(INADDR_ANY) &&
+                   c->mfc_mcastgrp == htonl(INADDR_ANY) &&
+                   c->mfc_un.res.ttls[vifi] < 255)
+                       return c;
+
+       return NULL;
+}
+
+/* Look for a (*,G) entry */
+static struct mfc_cache *ipmr_cache_find_any(struct mr_table *mrt,
+                                            __be32 mcastgrp, int vifi)
+{
+       int line = MFC_HASH(mcastgrp, htonl(INADDR_ANY));
+       struct mfc_cache *c, *proxy;
+
+       if (mcastgrp == htonl(INADDR_ANY))
+               goto skip;
+
+       list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
+               if (c->mfc_origin == htonl(INADDR_ANY) &&
+                   c->mfc_mcastgrp == mcastgrp) {
+                       if (c->mfc_un.res.ttls[vifi] < 255)
+                               return c;
+
+                       /* It's ok if the vifi is part of the static tree */
+                       proxy = ipmr_cache_find_any_parent(mrt,
+                                                          c->mfc_parent);
+                       if (proxy && proxy->mfc_un.res.ttls[vifi] < 255)
+                               return c;
+               }
+
+skip:
+       return ipmr_cache_find_any_parent(mrt, vifi);
+}
+
 /*
  *     Allocate a multicast cache entry
  */
@@ -1053,7 +1096,7 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
  *     MFC cache manipulation by user space mroute daemon
  */
 
-static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
+static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc, int parent)
 {
        int line;
        struct mfc_cache *c, *next;
@@ -1062,7 +1105,8 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
 
        list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) {
                if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
-                   c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
+                   c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
+                   (parent == -1 || parent == c->mfc_parent)) {
                        list_del_rcu(&c->list);
                        mroute_netlink_event(mrt, c, RTM_DELROUTE);
                        ipmr_cache_free(c);
@@ -1073,7 +1117,7 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
 }
 
 static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
-                       struct mfcctl *mfc, int mrtsock)
+                       struct mfcctl *mfc, int mrtsock, int parent)
 {
        bool found = false;
        int line;
@@ -1086,7 +1130,8 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
 
        list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
                if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
-                   c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
+                   c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
+                   (parent == -1 || parent == c->mfc_parent)) {
                        found = true;
                        break;
                }
@@ -1103,7 +1148,8 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
                return 0;
        }
 
-       if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
+       if (mfc->mfcc_mcastgrp.s_addr != htonl(INADDR_ANY) &&
+           !ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
                return -EINVAL;
 
        c = ipmr_cache_alloc();
@@ -1218,7 +1264,7 @@ static void mrtsock_destruct(struct sock *sk)
 
 int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
 {
-       int ret;
+       int ret, parent = 0;
        struct vifctl vif;
        struct mfcctl mfc;
        struct net *net = sock_net(sk);
@@ -1287,16 +1333,22 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
                 */
        case MRT_ADD_MFC:
        case MRT_DEL_MFC:
+               parent = -1;
+       case MRT_ADD_MFC_PROXY:
+       case MRT_DEL_MFC_PROXY:
                if (optlen != sizeof(mfc))
                        return -EINVAL;
                if (copy_from_user(&mfc, optval, sizeof(mfc)))
                        return -EFAULT;
+               if (parent == 0)
+                       parent = mfc.mfcc_parent;
                rtnl_lock();
-               if (optname == MRT_DEL_MFC)
-                       ret = ipmr_mfc_delete(mrt, &mfc);
+               if (optname == MRT_DEL_MFC || optname == MRT_DEL_MFC_PROXY)
+                       ret = ipmr_mfc_delete(mrt, &mfc, parent);
                else
                        ret = ipmr_mfc_add(net, mrt, &mfc,
-                                          sk == rtnl_dereference(mrt->mroute_sk));
+                                          sk == rtnl_dereference(mrt->mroute_sk),
+                                          parent);
                rtnl_unlock();
                return ret;
                /*
@@ -1749,17 +1801,28 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
 {
        int psend = -1;
        int vif, ct;
+       int true_vifi = ipmr_find_vif(mrt, skb->dev);
 
        vif = cache->mfc_parent;
        cache->mfc_un.res.pkt++;
        cache->mfc_un.res.bytes += skb->len;
 
+       if (cache->mfc_origin == htonl(INADDR_ANY) && true_vifi >= 0) {
+               struct mfc_cache *cache_proxy;
+
+               /* For an (*,G) entry, we only check that the incomming
+                * interface is part of the static tree.
+                */
+               cache_proxy = ipmr_cache_find_any_parent(mrt, vif);
+               if (cache_proxy &&
+                   cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
+                       goto forward;
+       }
+
        /*
         * Wrong interface: drop packet and (maybe) send PIM assert.
         */
        if (mrt->vif_table[vif].dev != skb->dev) {
-               int true_vifi;
-
                if (rt_is_output_route(skb_rtable(skb))) {
                        /* It is our own packet, looped back.
                         * Very complicated situation...
@@ -1776,7 +1839,6 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
                }
 
                cache->mfc_un.res.wrong_if++;
-               true_vifi = ipmr_find_vif(mrt, skb->dev);
 
                if (true_vifi >= 0 && mrt->mroute_do_assert &&
                    /* pimsm uses asserts, when switching from RPT to SPT,
@@ -1794,15 +1856,34 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
                goto dont_forward;
        }
 
+forward:
        mrt->vif_table[vif].pkt_in++;
        mrt->vif_table[vif].bytes_in += skb->len;
 
        /*
         *      Forward the frame
         */
+       if (cache->mfc_origin == htonl(INADDR_ANY) &&
+           cache->mfc_mcastgrp == htonl(INADDR_ANY)) {
+               if (true_vifi >= 0 &&
+                   true_vifi != cache->mfc_parent &&
+                   ip_hdr(skb)->ttl >
+                               cache->mfc_un.res.ttls[cache->mfc_parent]) {
+                       /* It's an (*,*) entry and the packet is not coming from
+                        * the upstream: forward the packet to the upstream
+                        * only.
+                        */
+                       psend = cache->mfc_parent;
+                       goto last_forward;
+               }
+               goto dont_forward;
+       }
        for (ct = cache->mfc_un.res.maxvif - 1;
             ct >= cache->mfc_un.res.minvif; ct--) {
-               if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
+               /* For (*,G) entry, don't forward to the incoming interface */
+               if ((cache->mfc_origin != htonl(INADDR_ANY) ||
+                    ct != true_vifi) &&
+                   ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
                        if (psend != -1) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
@@ -1813,6 +1894,7 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
                        psend = ct;
                }
        }
+last_forward:
        if (psend != -1) {
                if (local) {
                        struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
@@ -1902,6 +1984,13 @@ int ip_mr_input(struct sk_buff *skb)
 
        /* already under rcu_read_lock() */
        cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
+       if (cache == NULL) {
+               int vif = ipmr_find_vif(mrt, skb->dev);
+
+               if (vif >= 0)
+                       cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr,
+                                                   vif);
+       }
 
        /*
         *      No usable cache entry
@@ -2107,7 +2196,12 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
 
        rcu_read_lock();
        cache = ipmr_cache_find(mrt, saddr, daddr);
+       if (cache == NULL && skb->dev) {
+               int vif = ipmr_find_vif(mrt, skb->dev);
 
+               if (vif >= 0)
+                       cache = ipmr_cache_find_any(mrt, daddr, vif);
+       }
        if (cache == NULL) {
                struct sk_buff *skb2;
                struct iphdr *iph;
index 3ea4127404d662f6756155128054d4a4c9b4ba0a..7dc6a97435925d1b56a918906553b423accee999 100644 (file)
@@ -901,7 +901,7 @@ static int get_info(struct net *net, void __user *user,
 #endif
        t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
                                    "arptable_%s", name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                struct arpt_getinfo info;
                const struct xt_table_info *private = t->private;
 #ifdef CONFIG_COMPAT
@@ -958,7 +958,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
        }
 
        t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                const struct xt_table_info *private = t->private;
 
                duprintf("t->private->number = %u\n",
@@ -1001,7 +1001,7 @@ static int __do_replace(struct net *net, const char *name,
 
        t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
                                    "arptable_%s", name);
-       if (!t || IS_ERR(t)) {
+       if (IS_ERR_OR_NULL(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free_newinfo_counters_untrans;
        }
@@ -1158,7 +1158,7 @@ static int do_add_counters(struct net *net, const void __user *user,
        }
 
        t = xt_find_table_lock(net, NFPROTO_ARP, name);
-       if (!t || IS_ERR(t)) {
+       if (IS_ERR_OR_NULL(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
        }
@@ -1646,7 +1646,7 @@ static int compat_get_entries(struct net *net,
 
        xt_compat_lock(NFPROTO_ARP);
        t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                const struct xt_table_info *private = t->private;
                struct xt_table_info info;
 
index 17c5e06da6628b7ec12495471d3bfcc943acf969..3efcf87400c3420f7d2d877b7472f2d4aeea00a1 100644 (file)
@@ -1090,7 +1090,7 @@ static int get_info(struct net *net, void __user *user,
 #endif
        t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
                                    "iptable_%s", name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                struct ipt_getinfo info;
                const struct xt_table_info *private = t->private;
 #ifdef CONFIG_COMPAT
@@ -1149,7 +1149,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr,
        }
 
        t = xt_find_table_lock(net, AF_INET, get.name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                const struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n", private->number);
                if (get.size == private->size)
@@ -1189,7 +1189,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
 
        t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
                                    "iptable_%s", name);
-       if (!t || IS_ERR(t)) {
+       if (IS_ERR_OR_NULL(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free_newinfo_counters_untrans;
        }
@@ -1347,7 +1347,7 @@ do_add_counters(struct net *net, const void __user *user,
        }
 
        t = xt_find_table_lock(net, AF_INET, name);
-       if (!t || IS_ERR(t)) {
+       if (IS_ERR_OR_NULL(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
        }
@@ -1931,7 +1931,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
 
        xt_compat_lock(AF_INET);
        t = xt_find_table_lock(net, AF_INET, get.name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                const struct xt_table_info *private = t->private;
                struct xt_table_info info;
                duprintf("t->private->number = %u\n", private->number);
index fcdd0c2406e6d85d888633222e6697bd2352db86..48990ada0e1ecb698e0ff0439533c5afce591519 100644 (file)
@@ -420,54 +420,43 @@ static int ipv4_net_init(struct net *net)
 {
        int ret = 0;
 
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_tcp4);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp4);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_tcp4 :protocol register failed\n");
+               pr_err("nf_conntrack_tcp4: pernet registration failed\n");
                goto out_tcp;
        }
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_udp4);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp4);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_udp4 :protocol register failed\n");
+               pr_err("nf_conntrack_udp4: pernet registration failed\n");
                goto out_udp;
        }
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_icmp);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmp);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_icmp4 :protocol register failed\n");
+               pr_err("nf_conntrack_icmp4: pernet registration failed\n");
                goto out_icmp;
        }
-       ret = nf_conntrack_l3proto_register(net,
-                                           &nf_conntrack_l3proto_ipv4);
+       ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv4);
        if (ret < 0) {
-               pr_err("nf_conntrack_l3proto_ipv4 :protocol register failed\n");
+               pr_err("nf_conntrack_ipv4: pernet registration failed\n");
                goto out_ipv4;
        }
        return 0;
 out_ipv4:
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_icmp);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmp);
 out_icmp:
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_udp4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp4);
 out_udp:
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_tcp4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp4);
 out_tcp:
        return ret;
 }
 
 static void ipv4_net_exit(struct net *net)
 {
-       nf_conntrack_l3proto_unregister(net,
-                                       &nf_conntrack_l3proto_ipv4);
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_icmp);
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_udp4);
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_tcp4);
+       nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmp);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp4);
 }
 
 static struct pernet_operations ipv4_net_ops = {
@@ -500,16 +489,49 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
                pr_err("nf_conntrack_ipv4: can't register hooks.\n");
                goto cleanup_pernet;
        }
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv4: can't register tcp4 proto.\n");
+               goto cleanup_hooks;
+       }
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv4: can't register udp4 proto.\n");
+               goto cleanup_tcp4;
+       }
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmp);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv4: can't register icmpv4 proto.\n");
+               goto cleanup_udp4;
+       }
+
+       ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv4: can't register ipv4 proto.\n");
+               goto cleanup_icmpv4;
+       }
+
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
        ret = nf_conntrack_ipv4_compat_init();
        if (ret < 0)
-               goto cleanup_hooks;
+               goto cleanup_proto;
 #endif
        return ret;
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+ cleanup_proto:
+       nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
+#endif
+ cleanup_icmpv4:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmp);
+ cleanup_udp4:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp4);
+ cleanup_tcp4:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
  cleanup_hooks:
        nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
-#endif
  cleanup_pernet:
        unregister_pernet_subsys(&ipv4_net_ops);
  cleanup_sockopt:
@@ -523,6 +545,10 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void)
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
        nf_conntrack_ipv4_compat_fini();
 #endif
+       nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmp);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp4);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
        nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
        unregister_pernet_subsys(&ipv4_net_ops);
        nf_unregister_sockopt(&so_getorigdst);
index b236ef04914f99585455269fe2c9a18241088461..ef54377fb11cbdd3f327fa29c45c623923b8cb2f 100644 (file)
@@ -232,7 +232,8 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
  *
  * return false if we decode an option that should not be.
  */
-bool cookie_check_timestamp(struct tcp_options_received *tcp_opt, bool *ecn_ok)
+bool cookie_check_timestamp(struct tcp_options_received *tcp_opt,
+                       struct net *net, bool *ecn_ok)
 {
        /* echoed timestamp, lowest bits contain options */
        u32 options = tcp_opt->rcv_tsecr & TSMASK;
@@ -247,7 +248,7 @@ bool cookie_check_timestamp(struct tcp_options_received *tcp_opt, bool *ecn_ok)
 
        tcp_opt->sack_ok = (options & (1 << 4)) ? TCP_SACK_SEEN : 0;
        *ecn_ok = (options >> 5) & 1;
-       if (*ecn_ok && !sysctl_tcp_ecn)
+       if (*ecn_ok && !net->ipv4.sysctl_tcp_ecn)
                return false;
 
        if (tcp_opt->sack_ok && !sysctl_tcp_sack)
@@ -295,7 +296,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
        memset(&tcp_opt, 0, sizeof(tcp_opt));
        tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
 
-       if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+       if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
                goto out;
 
        ret = NULL;
index d84400b65049e61bc64f8f8eef37e2be2aaf2eda..2622707602d1276649a6d8514dba66b2290fd549 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/tcp_memcontrol.h>
 
 static int zero;
+static int one = 1;
 static int two = 2;
 static int tcp_retr1_max = 255;
 static int ip_local_port_range_min[] = { 1, 1 };
@@ -232,8 +233,8 @@ static int ipv4_tcp_mem(ctl_table *ctl, int write,
        return 0;
 }
 
-int proc_tcp_fastopen_key(ctl_table *ctl, int write, void __user *buffer,
-                         size_t *lenp, loff_t *ppos)
+static int proc_tcp_fastopen_key(ctl_table *ctl, int write, void __user *buffer,
+                                size_t *lenp, loff_t *ppos)
 {
        ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) };
        struct tcp_fastopen_context *ctxt;
@@ -537,13 +538,6 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       {
-               .procname       = "tcp_ecn",
-               .data           = &sysctl_tcp_ecn,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec
-       },
        {
                .procname       = "tcp_dsack",
                .data           = &sysctl_tcp_dsack,
@@ -556,14 +550,16 @@ static struct ctl_table ipv4_table[] = {
                .data           = &sysctl_tcp_wmem,
                .maxlen         = sizeof(sysctl_tcp_wmem),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
        },
        {
                .procname       = "tcp_rmem",
                .data           = &sysctl_tcp_rmem,
                .maxlen         = sizeof(sysctl_tcp_rmem),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
        },
        {
                .procname       = "tcp_app_win",
@@ -786,7 +782,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(sysctl_udp_rmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero
+               .extra1         = &one
        },
        {
                .procname       = "udp_wmem_min",
@@ -794,7 +790,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(sysctl_udp_wmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero
+               .extra1         = &one
        },
        { }
 };
@@ -849,6 +845,13 @@ static struct ctl_table ipv4_net_table[] = {
                .mode           = 0644,
                .proc_handler   = ipv4_ping_group_range,
        },
+       {
+               .procname       = "tcp_ecn",
+               .data           = &init_net.ipv4.sysctl_tcp_ecn,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
        {
                .procname       = "tcp_mem",
                .maxlen         = sizeof(init_net.ipv4.sysctl_tcp_mem),
@@ -882,6 +885,8 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
                        &net->ipv4.sysctl_icmp_ratemask;
                table[6].data =
                        &net->ipv4.sysctl_ping_group_range;
+               table[7].data =
+                       &net->ipv4.sysctl_tcp_ecn;
 
                /* Don't export sysctls to unprivileged users */
                if (net->user_ns != &init_user_ns)
index 2aa69c8ae60c1990c76e69fe5aef46b990b6da6e..3ec1f69c5ceb2ed0670c242c7eab2c0ac579c285 100644 (file)
@@ -896,6 +896,8 @@ new_segment:
                        skb_fill_page_desc(skb, i, page, offset, copy);
                }
 
+               skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG;
+
                skb->len += copy;
                skb->data_len += copy;
                skb->truesize += copy;
@@ -3032,6 +3034,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
                               SKB_GSO_DODGY |
                               SKB_GSO_TCP_ECN |
                               SKB_GSO_TCPV6 |
+                              SKB_GSO_SHARED_FRAG |
                               0) ||
                             !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
                        goto out;
@@ -3243,7 +3246,7 @@ __tcp_alloc_md5sig_pool(struct sock *sk)
                struct crypto_hash *hash;
 
                hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
-               if (!hash || IS_ERR(hash))
+               if (IS_ERR_OR_NULL(hash))
                        goto out_free;
 
                per_cpu_ptr(pool, cpu)->md5_desc.tfm = hash;
index 18f97ca76b00223b25d0f6faed8a829c45fb95c8..492c7cfe14532aed43a1df27c433c76b2ab4cf68 100644 (file)
@@ -81,8 +81,6 @@ int sysctl_tcp_sack __read_mostly = 1;
 int sysctl_tcp_fack __read_mostly = 1;
 int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH;
 EXPORT_SYMBOL(sysctl_tcp_reordering);
-int sysctl_tcp_ecn __read_mostly = 2;
-EXPORT_SYMBOL(sysctl_tcp_ecn);
 int sysctl_tcp_dsack __read_mostly = 1;
 int sysctl_tcp_app_win __read_mostly = 31;
 int sysctl_tcp_adv_win_scale __read_mostly = 1;
@@ -1242,13 +1240,13 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
         */
        if (!skb_shinfo(prev)->gso_size) {
                skb_shinfo(prev)->gso_size = mss;
-               skb_shinfo(prev)->gso_type = sk->sk_gso_type;
+               skb_shinfo(prev)->gso_type |= sk->sk_gso_type;
        }
 
        /* CHECKME: To clear or not to clear? Mimics normal skb currently */
        if (skb_shinfo(skb)->gso_segs <= 1) {
                skb_shinfo(skb)->gso_size = 0;
-               skb_shinfo(skb)->gso_type = 0;
+               skb_shinfo(skb)->gso_type &= SKB_GSO_SHARED_FRAG;
        }
 
        /* Difference in this won't matter, both ACKed by the same cumul. ACK */
index 70b09ef2463b3678c5da4a1d5fc0edb4656e4940..5a1cfc692df0b89df03b50165a28d011cf529c9b 100644 (file)
@@ -656,7 +656,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
                 * no RST generated if md5 hash doesn't match.
                 */
                sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev),
-                                            &tcp_hashinfo, ip_hdr(skb)->daddr,
+                                            &tcp_hashinfo, ip_hdr(skb)->saddr,
+                                            th->source, ip_hdr(skb)->daddr,
                                             ntohs(th->source), inet_iif(skb));
                /* don't send rst if it can't find key */
                if (!sk1)
@@ -1567,7 +1568,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                goto drop_and_free;
 
        if (!want_cookie || tmp_opt.tstamp_ok)
-               TCP_ECN_create_request(req, skb);
+               TCP_ECN_create_request(req, skb, sock_net(sk));
 
        if (want_cookie) {
                isn = cookie_v4_init_sequence(sk, skb, &req->mss);
@@ -2073,6 +2074,7 @@ do_time_wait:
        case TCP_TW_SYN: {
                struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev),
                                                        &tcp_hashinfo,
+                                                       iph->saddr, th->source,
                                                        iph->daddr, th->dest,
                                                        inet_iif(skb));
                if (sk2) {
@@ -2887,6 +2889,7 @@ EXPORT_SYMBOL(tcp_prot);
 
 static int __net_init tcp_sk_init(struct net *net)
 {
+       net->ipv4.sysctl_tcp_ecn = 2;
        return 0;
 }
 
index 5d451593ef16f98c65379da619b08e3d47236bff..367e2ec01da1f25afcf067351bf17ce673851af6 100644 (file)
@@ -314,7 +314,7 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
 
        tp->ecn_flags = 0;
-       if (sysctl_tcp_ecn == 1) {
+       if (sock_net(sk)->ipv4.sysctl_tcp_ecn == 1) {
                TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;
                tp->ecn_flags = TCP_ECN_OK;
        }
@@ -1133,6 +1133,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
 static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
                                 unsigned int mss_now)
 {
+       skb_shinfo(skb)->gso_type &= SKB_GSO_SHARED_FRAG;
        if (skb->len <= mss_now || !sk_can_gso(sk) ||
            skb->ip_summed == CHECKSUM_NONE) {
                /* Avoid the costly divide in the normal
@@ -1140,11 +1141,10 @@ static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
                 */
                skb_shinfo(skb)->gso_segs = 1;
                skb_shinfo(skb)->gso_size = 0;
-               skb_shinfo(skb)->gso_type = 0;
        } else {
                skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now);
                skb_shinfo(skb)->gso_size = mss_now;
-               skb_shinfo(skb)->gso_type = sk->sk_gso_type;
+               skb_shinfo(skb)->gso_type |= sk->sk_gso_type;
        }
 }
 
index 1f4d405eafba746d2b8085132a740b17a6658c80..6791aac06ea9e4a71289ba8313e7c10b53f5f031 100644 (file)
@@ -139,6 +139,7 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
 {
        struct sock *sk2;
        struct hlist_nulls_node *node;
+       kuid_t uid = sock_i_uid(sk);
 
        sk_nulls_for_each(sk2, node, &hslot->head)
                if (net_eq(sock_net(sk2), net) &&
@@ -147,6 +148,8 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
                    (!sk2->sk_reuse || !sk->sk_reuse) &&
                    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
                     sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+                   (!sk2->sk_reuseport || !sk->sk_reuseport ||
+                     !uid_eq(uid, sock_i_uid(sk2))) &&
                    (*saddr_comp)(sk, sk2)) {
                        if (bitmap)
                                __set_bit(udp_sk(sk2)->udp_port_hash >> log,
@@ -169,6 +172,7 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num,
 {
        struct sock *sk2;
        struct hlist_nulls_node *node;
+       kuid_t uid = sock_i_uid(sk);
        int res = 0;
 
        spin_lock(&hslot2->lock);
@@ -179,6 +183,8 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num,
                    (!sk2->sk_reuse || !sk->sk_reuse) &&
                    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
                     sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+                   (!sk2->sk_reuseport || !sk->sk_reuseport ||
+                     !uid_eq(uid, sock_i_uid(sk2))) &&
                    (*saddr_comp)(sk, sk2)) {
                        res = 1;
                        break;
@@ -337,26 +343,26 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
                        !ipv6_only_sock(sk)) {
                struct inet_sock *inet = inet_sk(sk);
 
-               score = (sk->sk_family == PF_INET ? 1 : 0);
+               score = (sk->sk_family == PF_INET ? 2 : 1);
                if (inet->inet_rcv_saddr) {
                        if (inet->inet_rcv_saddr != daddr)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
                if (inet->inet_daddr) {
                        if (inet->inet_daddr != saddr)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
                if (inet->inet_dport) {
                        if (inet->inet_dport != sport)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
                if (sk->sk_bound_dev_if) {
                        if (sk->sk_bound_dev_if != dif)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
        }
        return score;
@@ -365,7 +371,6 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
 /*
  * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num)
  */
-#define SCORE2_MAX (1 + 2 + 2 + 2)
 static inline int compute_score2(struct sock *sk, struct net *net,
                                 __be32 saddr, __be16 sport,
                                 __be32 daddr, unsigned int hnum, int dif)
@@ -380,21 +385,21 @@ static inline int compute_score2(struct sock *sk, struct net *net,
                if (inet->inet_num != hnum)
                        return -1;
 
-               score = (sk->sk_family == PF_INET ? 1 : 0);
+               score = (sk->sk_family == PF_INET ? 2 : 1);
                if (inet->inet_daddr) {
                        if (inet->inet_daddr != saddr)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
                if (inet->inet_dport) {
                        if (inet->inet_dport != sport)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
                if (sk->sk_bound_dev_if) {
                        if (sk->sk_bound_dev_if != dif)
                                return -1;
-                       score += 2;
+                       score += 4;
                }
        }
        return score;
@@ -409,19 +414,29 @@ static struct sock *udp4_lib_lookup2(struct net *net,
 {
        struct sock *sk, *result;
        struct hlist_nulls_node *node;
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
 begin:
        result = NULL;
-       badness = -1;
+       badness = 0;
        udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) {
                score = compute_score2(sk, net, saddr, sport,
                                      daddr, hnum, dif);
                if (score > badness) {
                        result = sk;
                        badness = score;
-                       if (score == SCORE2_MAX)
-                               goto exact_match;
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet_ehashfn(net, daddr, hnum,
+                                                   saddr, htons(sport));
+                               matches = 1;
+                       }
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -431,9 +446,7 @@ begin:
         */
        if (get_nulls_value(node) != slot2)
                goto begin;
-
        if (result) {
-exact_match:
                if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2)))
                        result = NULL;
                else if (unlikely(compute_score2(result, net, saddr, sport,
@@ -457,7 +470,8 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
        unsigned short hnum = ntohs(dport);
        unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
        struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
        rcu_read_lock();
        if (hslot->count > 10) {
@@ -486,13 +500,24 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
        }
 begin:
        result = NULL;
-       badness = -1;
+       badness = 0;
        sk_nulls_for_each_rcu(sk, node, &hslot->head) {
                score = compute_score(sk, net, saddr, hnum, sport,
                                      daddr, dport, dif);
                if (score > badness) {
                        result = sk;
                        badness = score;
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet_ehashfn(net, daddr, hnum,
+                                                   saddr, htons(sport));
+                               matches = 1;
+                       }
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -971,7 +996,7 @@ back_from_confirm:
                                  sizeof(struct udphdr), &ipc, &rt,
                                  msg->msg_flags);
                err = PTR_ERR(skb);
-               if (skb && !IS_ERR(skb))
+               if (!IS_ERR_OR_NULL(skb))
                        err = udp_send_skb(skb, fl4);
                goto out;
        }
index 4ea244891b58283189e8b9de501173d8ef2261f7..309af19a0a0a6eb69ee1852b993c4173d2b32c49 100644 (file)
@@ -40,7 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 
-obj-y += addrconf_core.o exthdrs_core.o
+obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o
 obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
 
 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
index 420e563263840442a150c13098148921559c3f2d..7f7332b446992d6f01dc873eebe976e7ac433f12 100644 (file)
@@ -110,10 +110,6 @@ static inline u32 cstamp_delta(unsigned long cstamp)
        return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
 }
 
-#define ADDRCONF_TIMER_FUZZ_MINUS      (HZ > 50 ? HZ/50 : 1)
-#define ADDRCONF_TIMER_FUZZ            (HZ / 4)
-#define ADDRCONF_TIMER_FUZZ_MAX                (HZ)
-
 #ifdef CONFIG_SYSCTL
 static void addrconf_sysctl_register(struct inet6_dev *idev);
 static void addrconf_sysctl_unregister(struct inet6_dev *idev);
@@ -1051,7 +1047,7 @@ retry:
                ipv6_add_addr(idev, &addr, tmp_plen,
                              ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,
                              addr_flags) : NULL;
-       if (!ift || IS_ERR(ift)) {
+       if (IS_ERR_OR_NULL(ift)) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
                pr_info("%s: retry temporary address regeneration\n", __func__);
@@ -2079,7 +2075,7 @@ ok:
                                                    addr_type&IPV6_ADDR_SCOPE_MASK,
                                                    addr_flags);
 
-                       if (!ifp || IS_ERR(ifp)) {
+                       if (IS_ERR_OR_NULL(ifp)) {
                                in6_dev_put(in6_dev);
                                return;
                        }
index b043c60429bd45529111d56893dac55aae91427a..6b793bfc0e10b4fc42a5d7887e613d00e545ee70 100644 (file)
@@ -811,11 +811,10 @@ static struct pernet_operations inet6_net_ops = {
 
 static int __init inet6_init(void)
 {
-       struct sk_buff *dummy_skb;
        struct list_head *r;
        int err = 0;
 
-       BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb));
+       BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > FIELD_SIZEOF(struct sk_buff, cb));
 
        /* Register the socket-side information for inet6_create.  */
        for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
index 8edf2601065af07790500809b8dee9fad0fc8eaa..33be36398a786d0143ce8a8da0995f7966a22103 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/transp_v6.h>
 #include <net/ip6_route.h>
 #include <net/tcp_states.h>
+#include <net/dsfield.h>
 
 #include <linux/errqueue.h>
 #include <asm/uaccess.h>
@@ -356,12 +357,11 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
                sin->sin6_port = serr->port;
                sin->sin6_scope_id = 0;
                if (skb->protocol == htons(ETH_P_IPV6)) {
-                       sin->sin6_addr =
-                               *(struct in6_addr *)(nh + serr->addr_offset);
+                       const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset),
+                                                                 struct ipv6hdr, daddr);
+                       sin->sin6_addr = ip6h->daddr;
                        if (np->sndflow)
-                               sin->sin6_flowinfo =
-                                       (*(__be32 *)(nh + serr->addr_offset - 24) &
-                                        IPV6_FLOWINFO_MASK);
+                               sin->sin6_flowinfo = ip6_flowinfo(ip6h);
                        if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
                                sin->sin6_scope_id = IP6CB(skb)->iif;
                } else {
@@ -488,13 +488,14 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
        }
 
        if (np->rxopt.bits.rxtclass) {
-               int tclass = ipv6_tclass(ipv6_hdr(skb));
+               int tclass = ipv6_get_dsfield(ipv6_hdr(skb));
                put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
        }
 
-       if (np->rxopt.bits.rxflow && (*(__be32 *)nh & IPV6_FLOWINFO_MASK)) {
-               __be32 flowinfo = *(__be32 *)nh & IPV6_FLOWINFO_MASK;
-               put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
+       if (np->rxopt.bits.rxflow) {
+               __be32 flowinfo = ip6_flowinfo((struct ipv6hdr *)nh);
+               if (flowinfo)
+                       put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
        }
 
        /* HbH is allowed only once */
index 473f628f9f203d2e0c58466f32603ce50a330402..07a7d65a7cb6757bdac702b01e8284ad2402bf46 100644 (file)
@@ -553,7 +553,8 @@ static bool ipv6_hop_ra(struct sk_buff *skb, int optoff)
        const unsigned char *nh = skb_network_header(skb);
 
        if (nh[optoff + 1] == 2) {
-               IP6CB(skb)->ra = optoff;
+               IP6CB(skb)->flags |= IP6SKB_ROUTERALERT;
+               memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra));
                return true;
        }
        LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
index 30647857a375bce469c50071636b5aef6c5a33d7..b386a2ce4c6fdd4b01afe3903e6988fbdeaa2043 100644 (file)
@@ -32,6 +32,9 @@ int inet6_csk_bind_conflict(const struct sock *sk,
 {
        const struct sock *sk2;
        const struct hlist_node *node;
+       int reuse = sk->sk_reuse;
+       int reuseport = sk->sk_reuseport;
+       kuid_t uid = sock_i_uid((struct sock *)sk);
 
        /* We must walk the whole port owner list in this case. -DaveM */
        /*
@@ -42,11 +45,17 @@ int inet6_csk_bind_conflict(const struct sock *sk,
                if (sk != sk2 &&
                    (!sk->sk_bound_dev_if ||
                     !sk2->sk_bound_dev_if ||
-                    sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
-                   (!sk->sk_reuse || !sk2->sk_reuse ||
-                    sk2->sk_state == TCP_LISTEN) &&
-                    ipv6_rcv_saddr_equal(sk, sk2))
-                       break;
+                    sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
+                       if ((!reuse || !sk2->sk_reuse ||
+                            sk2->sk_state == TCP_LISTEN) &&
+                           (!reuseport || !sk2->sk_reuseport ||
+                            (sk2->sk_state != TCP_TIME_WAIT &&
+                             !uid_eq(uid,
+                                     sock_i_uid((struct sock *)sk2))))) {
+                               if (ipv6_rcv_saddr_equal(sk, sk2))
+                                       break;
+                       }
+               }
        }
 
        return node != NULL;
index dea17fd28e5037295d56cf517671b479a1bca825..32b4a1675d826d8ce50e36dbf314456075e1660e 100644 (file)
@@ -158,25 +158,38 @@ static inline int compute_score(struct sock *sk, struct net *net,
 }
 
 struct sock *inet6_lookup_listener(struct net *net,
-               struct inet_hashinfo *hashinfo, const struct in6_addr *daddr,
+               struct inet_hashinfo *hashinfo, const struct in6_addr *saddr,
+               const __be16 sport, const struct in6_addr *daddr,
                const unsigned short hnum, const int dif)
 {
        struct sock *sk;
        const struct hlist_nulls_node *node;
        struct sock *result;
-       int score, hiscore;
+       int score, hiscore, matches = 0, reuseport = 0;
+       u32 phash = 0;
        unsigned int hash = inet_lhashfn(net, hnum);
        struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
 
        rcu_read_lock();
 begin:
        result = NULL;
-       hiscore = -1;
+       hiscore = 0;
        sk_nulls_for_each(sk, node, &ilb->head) {
                score = compute_score(sk, net, hnum, daddr, dif);
                if (score > hiscore) {
                        hiscore = score;
                        result = sk;
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               phash = inet6_ehashfn(net, daddr, hnum,
+                                                     saddr, sport);
+                               matches = 1;
+                       }
+               } else if (score == hiscore && reuseport) {
+                       matches++;
+                       if (((u64)phash * matches) >> 32 == 0)
+                               result = sk;
+                       phash = next_pseudo_random32(phash);
                }
        }
        /*
diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c
new file mode 100644 (file)
index 0000000..72d198b
--- /dev/null
@@ -0,0 +1,97 @@
+#include <net/ip.h>
+#include <net/udp.h>
+#include <net/udplite.h>
+#include <asm/checksum.h>
+
+#ifndef _HAVE_ARCH_IPV6_CSUM
+__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+                       const struct in6_addr *daddr,
+                       __u32 len, unsigned short proto,
+                       __wsum csum)
+{
+
+       int carry;
+       __u32 ulen;
+       __u32 uproto;
+       __u32 sum = (__force u32)csum;
+
+       sum += (__force u32)saddr->s6_addr32[0];
+       carry = (sum < (__force u32)saddr->s6_addr32[0]);
+       sum += carry;
+
+       sum += (__force u32)saddr->s6_addr32[1];
+       carry = (sum < (__force u32)saddr->s6_addr32[1]);
+       sum += carry;
+
+       sum += (__force u32)saddr->s6_addr32[2];
+       carry = (sum < (__force u32)saddr->s6_addr32[2]);
+       sum += carry;
+
+       sum += (__force u32)saddr->s6_addr32[3];
+       carry = (sum < (__force u32)saddr->s6_addr32[3]);
+       sum += carry;
+
+       sum += (__force u32)daddr->s6_addr32[0];
+       carry = (sum < (__force u32)daddr->s6_addr32[0]);
+       sum += carry;
+
+       sum += (__force u32)daddr->s6_addr32[1];
+       carry = (sum < (__force u32)daddr->s6_addr32[1]);
+       sum += carry;
+
+       sum += (__force u32)daddr->s6_addr32[2];
+       carry = (sum < (__force u32)daddr->s6_addr32[2]);
+       sum += carry;
+
+       sum += (__force u32)daddr->s6_addr32[3];
+       carry = (sum < (__force u32)daddr->s6_addr32[3]);
+       sum += carry;
+
+       ulen = (__force u32)htonl((__u32) len);
+       sum += ulen;
+       carry = (sum < ulen);
+       sum += carry;
+
+       uproto = (__force u32)htonl(proto);
+       sum += uproto;
+       carry = (sum < uproto);
+       sum += carry;
+
+       return csum_fold((__force __wsum)sum);
+}
+EXPORT_SYMBOL(csum_ipv6_magic);
+#endif
+
+int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
+{
+       int err;
+
+       UDP_SKB_CB(skb)->partial_cov = 0;
+       UDP_SKB_CB(skb)->cscov = skb->len;
+
+       if (proto == IPPROTO_UDPLITE) {
+               err = udplite_checksum_init(skb, uh);
+               if (err)
+                       return err;
+       }
+
+       if (uh->check == 0) {
+               /* RFC 2460 section 8.1 says that we SHOULD log
+                  this error. Well, it is reasonable.
+                */
+               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
+               return 1;
+       }
+       if (skb->ip_summed == CHECKSUM_COMPLETE &&
+           !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+                            skb->len, proto, skb->csum))
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       if (!skb_csum_unnecessary(skb))
+               skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                                        &ipv6_hdr(skb)->daddr,
+                                                        skb->len, proto, 0));
+
+       return 0;
+}
+EXPORT_SYMBOL(udp6_csum_init);
index c727e471275199ef27039f79b95755803435211a..db91fe3466a3c1dc02df7d2b864c6b17b1218cb1 100644 (file)
@@ -772,9 +772,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
         *      Push down and install the IP header.
         */
        ipv6h = ipv6_hdr(skb);
-       *(__be32 *)ipv6h = fl6->flowlabel | htonl(0x60000000);
-       dsfield = INET_ECN_encapsulate(0, dsfield);
-       ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
+       ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel);
        ipv6h->hop_limit = tunnel->parms.hop_limit;
        ipv6h->nexthdr = proto;
        ipv6h->saddr = fl6->saddr;
@@ -1240,7 +1238,7 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
        struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen);
        __be16 *p = (__be16 *)(ipv6h+1);
 
-       *(__be32 *)ipv6h = t->fl.u.ip6.flowlabel | htonl(0x60000000);
+       ip6_flow_hdr(ipv6h, 0, t->fl.u.ip6.flowlabel);
        ipv6h->hop_limit = t->parms.hop_limit;
        ipv6h->nexthdr = NEXTHDR_GRE;
        ipv6h->saddr = t->parms.laddr;
index a52d864d562b4067e8f70db9e0fabbafe76b7fea..4ac5bf30e16adae9a2fe1e271f6e3a39adf2cbb2 100644 (file)
@@ -212,7 +212,7 @@ resubmit:
                        if (ipv6_addr_is_multicast(&hdr->daddr) &&
                            !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
                            &hdr->saddr) &&
-                           !ipv6_is_mld(skb, nexthdr))
+                           !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb)))
                                goto discard;
                }
                if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
@@ -280,10 +280,8 @@ int ip6_mc_input(struct sk_buff *skb)
                struct inet6_skb_parm *opt = IP6CB(skb);
 
                /* Check for MLD */
-               if (unlikely(opt->ra)) {
+               if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
                        /* Check if this is a mld message */
-                       u8 *ptr = skb_network_header(skb) + opt->ra;
-                       struct icmp6hdr *icmp6;
                        u8 nexthdr = hdr->nexthdr;
                        __be16 frag_off;
                        int offset;
@@ -291,7 +289,7 @@ int ip6_mc_input(struct sk_buff *skb)
                        /* Check if the value of Router Alert
                         * is for MLD (0x0000).
                         */
-                       if ((ptr[2] | ptr[3]) == 0) {
+                       if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) {
                                deliver = false;
 
                                if (!ipv6_ext_hdr(nexthdr)) {
@@ -303,24 +301,10 @@ int ip6_mc_input(struct sk_buff *skb)
                                if (offset < 0)
                                        goto out;
 
-                               if (nexthdr != IPPROTO_ICMPV6)
+                               if (!ipv6_is_mld(skb, nexthdr, offset))
                                        goto out;
 
-                               if (!pskb_may_pull(skb, (skb_network_header(skb) +
-                                                  offset + 1 - skb->data)))
-                                       goto out;
-
-                               icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);
-
-                               switch (icmp6->icmp6_type) {
-                               case ICMPV6_MGM_QUERY:
-                               case ICMPV6_MGM_REPORT:
-                               case ICMPV6_MGM_REDUCTION:
-                               case ICMPV6_MLD2_REPORT:
-                                       deliver = true;
-                                       break;
-                               }
-                               goto out;
+                               deliver = true;
                        }
                        /* unknown RA - process it normally */
                }
index f26f0da7f095763050d891e2543105c3f996320e..d141fc32a2eab7c41557488000e5811620ef799f 100644 (file)
@@ -100,6 +100,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
                       SKB_GSO_DODGY |
                       SKB_GSO_TCP_ECN |
                       SKB_GSO_TCPV6 |
+                      SKB_GSO_SHARED_FRAG |
                       0)))
                goto out;
 
index 0c7c03d50dc0342c7caad25c9d24c3931c50438b..906b7e6dd7fb9ff2f557801d109bf81a5b29f9f2 100644 (file)
@@ -56,8 +56,6 @@
 #include <net/checksum.h>
 #include <linux/mroute6.h>
 
-int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
-
 int __ip6_local_out(struct sk_buff *skb)
 {
        int len;
@@ -88,7 +86,8 @@ static int ip6_finish_output2(struct sk_buff *skb)
        struct dst_entry *dst = skb_dst(skb);
        struct net_device *dev = dst->dev;
        struct neighbour *neigh;
-       struct rt6_info *rt;
+       struct in6_addr *nexthop;
+       int ret;
 
        skb->protocol = htons(ETH_P_IPV6);
        skb->dev = dev;
@@ -123,10 +122,17 @@ static int ip6_finish_output2(struct sk_buff *skb)
                                skb->len);
        }
 
-       rt = (struct rt6_info *) dst;
-       neigh = rt->n;
-       if (neigh)
-               return dst_neigh_output(dst, neigh, skb);
+       rcu_read_lock_bh();
+       nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
+       neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
+       if (unlikely(!neigh))
+               neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
+       if (!IS_ERR(neigh)) {
+               ret = dst_neigh_output(dst, neigh, skb);
+               rcu_read_unlock_bh();
+               return ret;
+       }
+       rcu_read_unlock_bh();
 
        IP6_INC_STATS_BH(dev_net(dst->dev),
                         ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
@@ -216,7 +222,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        if (hlimit < 0)
                hlimit = ip6_dst_hoplimit(dst);
 
-       *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel;
+       ip6_flow_hdr(hdr, tclass, fl6->flowlabel);
 
        hdr->payload_len = htons(seg_len);
        hdr->nexthdr = proto;
@@ -246,39 +252,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
 
 EXPORT_SYMBOL(ip6_xmit);
 
-/*
- *     To avoid extra problems ND packets are send through this
- *     routine. It's code duplication but I really want to avoid
- *     extra checks since ipv6_build_header is used by TCP (which
- *     is for us performance critical)
- */
-
-int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
-              const struct in6_addr *saddr, const struct in6_addr *daddr,
-              int proto, int len)
-{
-       struct ipv6_pinfo *np = inet6_sk(sk);
-       struct ipv6hdr *hdr;
-
-       skb->protocol = htons(ETH_P_IPV6);
-       skb->dev = dev;
-
-       skb_reset_network_header(skb);
-       skb_put(skb, sizeof(struct ipv6hdr));
-       hdr = ipv6_hdr(skb);
-
-       *(__be32*)hdr = htonl(0x60000000);
-
-       hdr->payload_len = htons(len);
-       hdr->nexthdr = proto;
-       hdr->hop_limit = np->hop_limit;
-
-       hdr->saddr = *saddr;
-       hdr->daddr = *daddr;
-
-       return 0;
-}
-
 static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
 {
        struct ip6_ra_chain *ra;
@@ -913,8 +886,12 @@ static int ip6_dst_lookup_tail(struct sock *sk,
         * dst entry of the nexthop router
         */
        rt = (struct rt6_info *) *dst;
-       n = rt->n;
-       if (n && !(n->nud_state & NUD_VALID)) {
+       rcu_read_lock_bh();
+       n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt, &fl6->daddr));
+       err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0;
+       rcu_read_unlock_bh();
+
+       if (err) {
                struct inet6_ifaddr *ifp;
                struct flowi6 fl_gw6;
                int redirect;
@@ -1548,9 +1525,7 @@ int ip6_push_pending_frames(struct sock *sk)
        skb_reset_network_header(skb);
        hdr = ipv6_hdr(skb);
 
-       *(__be32*)hdr = fl6->flowlabel |
-                    htonl(0x60000000 | ((int)np->cork.tclass << 20));
-
+       ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel);
        hdr->hop_limit = np->cork.hop_limit;
        hdr->nexthdr = proto;
        hdr->saddr = fl6->saddr;
index a14f28b280f57a040e3d499955419f6c949c5c93..fff83cbc197f1cc22149698d0b8f54fea0d107e8 100644 (file)
@@ -1030,9 +1030,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        skb_push(skb, sizeof(struct ipv6hdr));
        skb_reset_network_header(skb);
        ipv6h = ipv6_hdr(skb);
-       *(__be32*)ipv6h = fl6->flowlabel | htonl(0x60000000);
-       dsfield = INET_ECN_encapsulate(0, dsfield);
-       ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
+       ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel);
        ipv6h->hop_limit = t->parms.hop_limit;
        ipv6h->nexthdr = proto;
        ipv6h->saddr = fl6->saddr;
index 8fd154e5f07966dd049bcdb8e93d9f7b8ab5452e..351ce98e90d963627247c0e65ce4b3a30649d3f2 100644 (file)
@@ -1017,6 +1017,50 @@ static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
        return NULL;
 }
 
+/* Look for a (*,*,oif) entry */
+static struct mfc6_cache *ip6mr_cache_find_any_parent(struct mr6_table *mrt,
+                                                     mifi_t mifi)
+{
+       int line = MFC6_HASH(&in6addr_any, &in6addr_any);
+       struct mfc6_cache *c;
+
+       list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
+               if (ipv6_addr_any(&c->mf6c_origin) &&
+                   ipv6_addr_any(&c->mf6c_mcastgrp) &&
+                   (c->mfc_un.res.ttls[mifi] < 255))
+                       return c;
+
+       return NULL;
+}
+
+/* Look for a (*,G) entry */
+static struct mfc6_cache *ip6mr_cache_find_any(struct mr6_table *mrt,
+                                              struct in6_addr *mcastgrp,
+                                              mifi_t mifi)
+{
+       int line = MFC6_HASH(mcastgrp, &in6addr_any);
+       struct mfc6_cache *c, *proxy;
+
+       if (ipv6_addr_any(mcastgrp))
+               goto skip;
+
+       list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
+               if (ipv6_addr_any(&c->mf6c_origin) &&
+                   ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) {
+                       if (c->mfc_un.res.ttls[mifi] < 255)
+                               return c;
+
+                       /* It's ok if the mifi is part of the static tree */
+                       proxy = ip6mr_cache_find_any_parent(mrt,
+                                                           c->mf6c_parent);
+                       if (proxy && proxy->mfc_un.res.ttls[mifi] < 255)
+                               return c;
+               }
+
+skip:
+       return ip6mr_cache_find_any_parent(mrt, mifi);
+}
+
 /*
  *     Allocate a multicast cache entry
  */
@@ -1247,7 +1291,8 @@ ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
  *     MFC6 cache manipulation by user space
  */
 
-static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
+static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc,
+                           int parent)
 {
        int line;
        struct mfc6_cache *c, *next;
@@ -1256,7 +1301,9 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
 
        list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
                if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
-                   ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
+                   ipv6_addr_equal(&c->mf6c_mcastgrp,
+                                   &mfc->mf6cc_mcastgrp.sin6_addr) &&
+                   (parent == -1 || parent == c->mf6c_parent)) {
                        write_lock_bh(&mrt_lock);
                        list_del(&c->list);
                        write_unlock_bh(&mrt_lock);
@@ -1391,7 +1438,7 @@ void ip6_mr_cleanup(void)
 }
 
 static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
-                        struct mf6cctl *mfc, int mrtsock)
+                        struct mf6cctl *mfc, int mrtsock, int parent)
 {
        bool found = false;
        int line;
@@ -1413,7 +1460,9 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
 
        list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
                if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
-                   ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
+                   ipv6_addr_equal(&c->mf6c_mcastgrp,
+                                   &mfc->mf6cc_mcastgrp.sin6_addr) &&
+                   (parent == -1 || parent == mfc->mf6cc_parent)) {
                        found = true;
                        break;
                }
@@ -1430,7 +1479,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
                return 0;
        }
 
-       if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
+       if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
+           !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
                return -EINVAL;
 
        c = ip6mr_cache_alloc();
@@ -1596,7 +1646,7 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
 
 int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
 {
-       int ret;
+       int ret, parent = 0;
        struct mif6ctl vif;
        struct mf6cctl mfc;
        mifi_t mifi;
@@ -1653,15 +1703,21 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
         */
        case MRT6_ADD_MFC:
        case MRT6_DEL_MFC:
+               parent = -1;
+       case MRT6_ADD_MFC_PROXY:
+       case MRT6_DEL_MFC_PROXY:
                if (optlen < sizeof(mfc))
                        return -EINVAL;
                if (copy_from_user(&mfc, optval, sizeof(mfc)))
                        return -EFAULT;
+               if (parent == 0)
+                       parent = mfc.mf6cc_parent;
                rtnl_lock();
-               if (optname == MRT6_DEL_MFC)
-                       ret = ip6mr_mfc_delete(mrt, &mfc);
+               if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
+                       ret = ip6mr_mfc_delete(mrt, &mfc, parent);
                else
-                       ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk);
+                       ret = ip6mr_mfc_add(net, mrt, &mfc,
+                                           sk == mrt->mroute6_sk, parent);
                rtnl_unlock();
                return ret;
 
@@ -2018,19 +2074,29 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
 {
        int psend = -1;
        int vif, ct;
+       int true_vifi = ip6mr_find_vif(mrt, skb->dev);
 
        vif = cache->mf6c_parent;
        cache->mfc_un.res.pkt++;
        cache->mfc_un.res.bytes += skb->len;
 
+       if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) {
+               struct mfc6_cache *cache_proxy;
+
+               /* For an (*,G) entry, we only check that the incomming
+                * interface is part of the static tree.
+                */
+               cache_proxy = ip6mr_cache_find_any_parent(mrt, vif);
+               if (cache_proxy &&
+                   cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
+                       goto forward;
+       }
+
        /*
         * Wrong interface: drop packet and (maybe) send PIM assert.
         */
        if (mrt->vif6_table[vif].dev != skb->dev) {
-               int true_vifi;
-
                cache->mfc_un.res.wrong_if++;
-               true_vifi = ip6mr_find_vif(mrt, skb->dev);
 
                if (true_vifi >= 0 && mrt->mroute_do_assert &&
                    /* pimsm uses asserts, when switching from RPT to SPT,
@@ -2048,14 +2114,32 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
                goto dont_forward;
        }
 
+forward:
        mrt->vif6_table[vif].pkt_in++;
        mrt->vif6_table[vif].bytes_in += skb->len;
 
        /*
         *      Forward the frame
         */
+       if (ipv6_addr_any(&cache->mf6c_origin) &&
+           ipv6_addr_any(&cache->mf6c_mcastgrp)) {
+               if (true_vifi >= 0 &&
+                   true_vifi != cache->mf6c_parent &&
+                   ipv6_hdr(skb)->hop_limit >
+                               cache->mfc_un.res.ttls[cache->mf6c_parent]) {
+                       /* It's an (*,*) entry and the packet is not coming from
+                        * the upstream: forward the packet to the upstream
+                        * only.
+                        */
+                       psend = cache->mf6c_parent;
+                       goto last_forward;
+               }
+               goto dont_forward;
+       }
        for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) {
-               if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
+               /* For (*,G) entry, don't forward to the incoming interface */
+               if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) &&
+                   ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
                        if (psend != -1) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
                                if (skb2)
@@ -2064,6 +2148,7 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
                        psend = ct;
                }
        }
+last_forward:
        if (psend != -1) {
                ip6mr_forward2(net, mrt, skb, cache, psend);
                return 0;
@@ -2099,6 +2184,14 @@ int ip6_mr_input(struct sk_buff *skb)
        read_lock(&mrt_lock);
        cache = ip6mr_cache_find(mrt,
                                 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
+       if (cache == NULL) {
+               int vif = ip6mr_find_vif(mrt, skb->dev);
+
+               if (vif >= 0)
+                       cache = ip6mr_cache_find_any(mrt,
+                                                    &ipv6_hdr(skb)->daddr,
+                                                    vif);
+       }
 
        /*
         *      No usable cache entry
@@ -2186,6 +2279,13 @@ int ip6mr_get_route(struct net *net,
 
        read_lock(&mrt_lock);
        cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
+       if (!cache && skb->dev) {
+               int vif = ip6mr_find_vif(mrt, skb->dev);
+
+               if (vif >= 0)
+                       cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
+                                                    vif);
+       }
 
        if (!cache) {
                struct sk_buff *skb2;
index 28dfa5f3801febb37cfd4ab17e010be4cc936e24..f25002aaf624dd4bca40e7303930bc773e2132f5 100644 (file)
@@ -934,33 +934,6 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
        return err;
 }
 
-/*
- * identify MLD packets for MLD filter exceptions
- */
-bool ipv6_is_mld(struct sk_buff *skb, int nexthdr)
-{
-       struct icmp6hdr *pic;
-
-       if (nexthdr != IPPROTO_ICMPV6)
-               return false;
-
-       if (!pskb_may_pull(skb, sizeof(struct icmp6hdr)))
-               return false;
-
-       pic = icmp6_hdr(skb);
-
-       switch (pic->icmp6_type) {
-       case ICMPV6_MGM_QUERY:
-       case ICMPV6_MGM_REPORT:
-       case ICMPV6_MGM_REDUCTION:
-       case ICMPV6_MLD2_REPORT:
-               return true;
-       default:
-               break;
-       }
-       return false;
-}
-
 /*
  *     check if the interface/address pair is valid
  */
@@ -1340,6 +1313,31 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
        return scount;
 }
 
+static void ip6_mc_hdr(struct sock *sk, struct sk_buff *skb,
+                      struct net_device *dev,
+                      const struct in6_addr *saddr,
+                      const struct in6_addr *daddr,
+                      int proto, int len)
+{
+       struct ipv6hdr *hdr;
+
+       skb->protocol = htons(ETH_P_IPV6);
+       skb->dev = dev;
+
+       skb_reset_network_header(skb);
+       skb_put(skb, sizeof(struct ipv6hdr));
+       hdr = ipv6_hdr(skb);
+
+       ip6_flow_hdr(hdr, 0, 0);
+
+       hdr->payload_len = htons(len);
+       hdr->nexthdr = proto;
+       hdr->hop_limit = inet6_sk(sk)->hop_limit;
+
+       hdr->saddr = *saddr;
+       hdr->daddr = *daddr;
+}
+
 static struct sk_buff *mld_newpack(struct net_device *dev, int size)
 {
        struct net *net = dev_net(dev);
@@ -1375,7 +1373,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
        } else
                saddr = &addr_buf;
 
-       ip6_nd_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0);
+       ip6_mc_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0);
 
        memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
 
@@ -1418,7 +1416,7 @@ static void mld_sendpack(struct sk_buff *skb)
        icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT,
                         &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
                         skb->dev->ifindex);
-       dst = icmp6_dst_alloc(skb->dev, NULL, &fl6);
+       dst = icmp6_dst_alloc(skb->dev, &fl6);
 
        err = 0;
        if (IS_ERR(dst)) {
@@ -1767,7 +1765,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
        } else
                saddr = &addr_buf;
 
-       ip6_nd_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len);
+       ip6_mc_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len);
 
        memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
 
@@ -1786,7 +1784,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
        icmpv6_flow_init(sk, &fl6, type,
                         &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
                         skb->dev->ifindex);
-       dst = icmp6_dst_alloc(skb->dev, NULL, &fl6);
+       dst = icmp6_dst_alloc(skb->dev, &fl6);
        if (IS_ERR(dst)) {
                err = PTR_ERR(dst);
                goto err_out;
index 6574175795df8d6938e6c4bf62d37171dbd0be9c..76ef4353d51872c1688b52531eadf1f4f446a8a4 100644 (file)
@@ -143,16 +143,12 @@ struct neigh_table nd_tbl = {
        .gc_thresh3 =   1024,
 };
 
-static inline int ndisc_opt_addr_space(struct net_device *dev)
+static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
 {
-       return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
-}
-
-static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
-                                 unsigned short addr_type)
-{
-       int pad   = ndisc_addr_option_pad(addr_type);
-       int space = NDISC_OPT_SPACE(data_len + pad);
+       int pad   = ndisc_addr_option_pad(skb->dev->type);
+       int data_len = skb->dev->addr_len;
+       int space = ndisc_opt_addr_space(skb->dev);
+       u8 *opt = skb_put(skb, space);
 
        opt[0] = type;
        opt[1] = space>>3;
@@ -166,7 +162,6 @@ static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
        opt += data_len;
        if ((space -= data_len) > 0)
                memset(opt, 0, space);
-       return opt + space;
 }
 
 static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
@@ -370,91 +365,88 @@ static void pndisc_destructor(struct pneigh_entry *n)
        ipv6_dev_mc_dec(dev, &maddr);
 }
 
-static struct sk_buff *ndisc_build_skb(struct net_device *dev,
-                                      const struct in6_addr *daddr,
-                                      const struct in6_addr *saddr,
-                                      struct icmp6hdr *icmp6h,
-                                      const struct in6_addr *target,
-                                      int llinfo)
+static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
+                                      int len)
 {
-       struct net *net = dev_net(dev);
-       struct sock *sk = net->ipv6.ndisc_sk;
-       struct sk_buff *skb;
-       struct icmp6hdr *hdr;
        int hlen = LL_RESERVED_SPACE(dev);
        int tlen = dev->needed_tailroom;
-       int len;
+       struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
+       struct sk_buff *skb;
        int err;
-       u8 *opt;
-
-       if (!dev->addr_len)
-               llinfo = 0;
-
-       len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
-       if (llinfo)
-               len += ndisc_opt_addr_space(dev);
 
        skb = sock_alloc_send_skb(sk,
-                                 (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                  len + hlen + tlen),
+                                 hlen + sizeof(struct ipv6hdr) + len + tlen,
                                  1, &err);
        if (!skb) {
-               ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n",
+               ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n",
                          __func__, err);
                return NULL;
        }
 
-       skb_reserve(skb, hlen);
-       ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
+       skb->protocol = htons(ETH_P_IPV6);
+       skb->dev = dev;
 
-       skb->transport_header = skb->tail;
-       skb_put(skb, len);
+       skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
+       skb_reset_transport_header(skb);
 
-       hdr = (struct icmp6hdr *)skb_transport_header(skb);
-       memcpy(hdr, icmp6h, sizeof(*hdr));
+       return skb;
+}
 
-       opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
-       if (target) {
-               *(struct in6_addr *)opt = *target;
-               opt += sizeof(*target);
-       }
+static void ip6_nd_hdr(struct sk_buff *skb,
+                      const struct in6_addr *saddr,
+                      const struct in6_addr *daddr,
+                      int hop_limit, int len)
+{
+       struct ipv6hdr *hdr;
 
-       if (llinfo)
-               ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
-                                      dev->addr_len, dev->type);
+       skb_push(skb, sizeof(*hdr));
+       skb_reset_network_header(skb);
+       hdr = ipv6_hdr(skb);
 
-       hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
-                                          IPPROTO_ICMPV6,
-                                          csum_partial(hdr,
-                                                       len, 0));
+       ip6_flow_hdr(hdr, 0, 0);
 
-       return skb;
+       hdr->payload_len = htons(len);
+       hdr->nexthdr = IPPROTO_ICMPV6;
+       hdr->hop_limit = hop_limit;
+
+       hdr->saddr = *saddr;
+       hdr->daddr = *daddr;
 }
 
-static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
-                          struct neighbour *neigh,
+static void ndisc_send_skb(struct sk_buff *skb,
                           const struct in6_addr *daddr,
-                          const struct in6_addr *saddr,
-                          struct icmp6hdr *icmp6h)
+                          const struct in6_addr *saddr)
 {
-       struct flowi6 fl6;
-       struct dst_entry *dst;
-       struct net *net = dev_net(dev);
+       struct dst_entry *dst = skb_dst(skb);
+       struct net *net = dev_net(skb->dev);
        struct sock *sk = net->ipv6.ndisc_sk;
        struct inet6_dev *idev;
        int err;
+       struct icmp6hdr *icmp6h = icmp6_hdr(skb);
        u8 type;
 
        type = icmp6h->icmp6_type;
 
-       icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
-       dst = icmp6_dst_alloc(dev, neigh, &fl6);
-       if (IS_ERR(dst)) {
-               kfree_skb(skb);
-               return;
+       if (!dst) {
+               struct sock *sk = net->ipv6.ndisc_sk;
+               struct flowi6 fl6;
+
+               icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
+               dst = icmp6_dst_alloc(skb->dev, &fl6);
+               if (IS_ERR(dst)) {
+                       kfree_skb(skb);
+                       return;
+               }
+
+               skb_dst_set(skb, dst);
        }
 
-       skb_dst_set(skb, dst);
+       icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
+                                             IPPROTO_ICMPV6,
+                                             csum_partial(icmp6h,
+                                                          skb->len, 0));
+
+       ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
 
        rcu_read_lock();
        idev = __in6_dev_get(dst->dev);
@@ -470,36 +462,17 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
        rcu_read_unlock();
 }
 
-/*
- *     Send a Neighbour Discover packet
- */
-static void __ndisc_send(struct net_device *dev,
-                        struct neighbour *neigh,
-                        const struct in6_addr *daddr,
-                        const struct in6_addr *saddr,
-                        struct icmp6hdr *icmp6h, const struct in6_addr *target,
-                        int llinfo)
-{
-       struct sk_buff *skb;
-
-       skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
-       if (!skb)
-               return;
-
-       ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
-}
-
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
                          const struct in6_addr *daddr,
                          const struct in6_addr *solicited_addr,
-                         int router, int solicited, int override, int inc_opt)
+                         bool router, bool solicited, bool override, bool inc_opt)
 {
+       struct sk_buff *skb;
        struct in6_addr tmpaddr;
        struct inet6_ifaddr *ifp;
        const struct in6_addr *src_addr;
-       struct icmp6hdr icmp6h = {
-               .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
-       };
+       struct nd_msg *msg;
+       int optlen = 0;
 
        /* for anycast or proxy, solicited_addr != src_addr */
        ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
@@ -517,13 +490,32 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
                src_addr = &tmpaddr;
        }
 
-       icmp6h.icmp6_router = router;
-       icmp6h.icmp6_solicited = solicited;
-       icmp6h.icmp6_override = override;
+       if (!dev->addr_len)
+               inc_opt = 0;
+       if (inc_opt)
+               optlen += ndisc_opt_addr_space(dev);
+
+       skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
+       if (!skb)
+               return;
 
-       __ndisc_send(dev, neigh, daddr, src_addr,
-                    &icmp6h, solicited_addr,
-                    inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
+       msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
+       *msg = (struct nd_msg) {
+               .icmph = {
+                       .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
+                       .icmp6_router = router,
+                       .icmp6_solicited = solicited,
+                       .icmp6_override = override,
+               },
+               .target = *solicited_addr,
+       };
+
+       if (inc_opt)
+               ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
+                                      dev->dev_addr);
+
+
+       ndisc_send_skb(skb, daddr, src_addr);
 }
 
 static void ndisc_send_unsol_na(struct net_device *dev)
@@ -551,10 +543,11 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
                   const struct in6_addr *solicit,
                   const struct in6_addr *daddr, const struct in6_addr *saddr)
 {
+       struct sk_buff *skb;
        struct in6_addr addr_buf;
-       struct icmp6hdr icmp6h = {
-               .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
-       };
+       int inc_opt = dev->addr_len;
+       int optlen = 0;
+       struct nd_msg *msg;
 
        if (saddr == NULL) {
                if (ipv6_get_lladdr(dev, &addr_buf,
@@ -563,18 +556,37 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
                saddr = &addr_buf;
        }
 
-       __ndisc_send(dev, neigh, daddr, saddr,
-                    &icmp6h, solicit,
-                    !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
+       if (ipv6_addr_any(saddr))
+               inc_opt = 0;
+       if (inc_opt)
+               optlen += ndisc_opt_addr_space(dev);
+
+       skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
+       if (!skb)
+               return;
+
+       msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
+       *msg = (struct nd_msg) {
+               .icmph = {
+                       .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
+               },
+               .target = *solicit,
+       };
+
+       if (inc_opt)
+               ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
+                                      dev->dev_addr);
+
+       ndisc_send_skb(skb, daddr, saddr);
 }
 
 void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
                   const struct in6_addr *daddr)
 {
-       struct icmp6hdr icmp6h = {
-               .icmp6_type = NDISC_ROUTER_SOLICITATION,
-       };
+       struct sk_buff *skb;
+       struct rs_msg *msg;
        int send_sllao = dev->addr_len;
+       int optlen = 0;
 
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
        /*
@@ -598,9 +610,27 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
                }
        }
 #endif
-       __ndisc_send(dev, NULL, daddr, saddr,
-                    &icmp6h, NULL,
-                    send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
+       if (!dev->addr_len)
+               send_sllao = 0;
+       if (send_sllao)
+               optlen += ndisc_opt_addr_space(dev);
+
+       skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
+       if (!skb)
+               return;
+
+       msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
+       *msg = (struct rs_msg) {
+               .icmph = {
+                       .icmp6_type = NDISC_ROUTER_SOLICITATION,
+               },
+       };
+
+       if (send_sllao)
+               ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
+                                      dev->dev_addr);
+
+       ndisc_send_skb(skb, daddr, saddr);
 }
 
 
@@ -676,6 +706,11 @@ static void ndisc_recv_ns(struct sk_buff *skb)
        bool inc;
        int is_router = -1;
 
+       if (skb->len < sizeof(struct nd_msg)) {
+               ND_PRINTK(2, warn, "NS: packet too short\n");
+               return;
+       }
+
        if (ipv6_addr_is_multicast(&msg->target)) {
                ND_PRINTK(2, warn, "NS: multicast target address\n");
                return;
@@ -685,11 +720,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
         * RFC2461 7.1.1:
         * DAD has to be destined for solicited node multicast address.
         */
-       if (dad &&
-           !(daddr->s6_addr32[0] == htonl(0xff020000) &&
-             daddr->s6_addr32[1] == htonl(0x00000000) &&
-             daddr->s6_addr32[2] == htonl(0x00000001) &&
-             daddr->s6_addr [12] == 0xff )) {
+       if (dad && !ipv6_addr_is_solict_mult(daddr)) {
                ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
                return;
        }
@@ -780,11 +811,11 @@ static void ndisc_recv_ns(struct sk_buff *skb)
        }
 
        if (is_router < 0)
-               is_router = !!idev->cnf.forwarding;
+               is_router = idev->cnf.forwarding;
 
        if (dad) {
                ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
-                             is_router, 0, (ifp != NULL), 1);
+                             !!is_router, false, (ifp != NULL), true);
                goto out;
        }
 
@@ -805,8 +836,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                             NEIGH_UPDATE_F_OVERRIDE);
        if (neigh || !dev->header_ops) {
                ndisc_send_na(dev, neigh, saddr, &msg->target,
-                             is_router,
-                             1, (ifp != NULL && inc), inc);
+                             !!is_router,
+                             true, (ifp != NULL && inc), inc);
                if (neigh)
                        neigh_release(neigh);
        }
@@ -1350,25 +1381,34 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
        icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
 }
 
+static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
+                                          struct sk_buff *orig_skb,
+                                          int rd_len)
+{
+       u8 *opt = skb_put(skb, rd_len);
+
+       memset(opt, 0, 8);
+       *(opt++) = ND_OPT_REDIRECT_HDR;
+       *(opt++) = (rd_len >> 3);
+       opt += 6;
+
+       memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
+}
+
 void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 {
        struct net_device *dev = skb->dev;
        struct net *net = dev_net(dev);
        struct sock *sk = net->ipv6.ndisc_sk;
-       int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+       int optlen = 0;
        struct inet_peer *peer;
        struct sk_buff *buff;
-       struct icmp6hdr *icmph;
+       struct rd_msg *msg;
        struct in6_addr saddr_buf;
-       struct in6_addr *addrp;
        struct rt6_info *rt;
        struct dst_entry *dst;
-       struct inet6_dev *idev;
        struct flowi6 fl6;
-       u8 *opt;
-       int hlen, tlen;
        int rd_len;
-       int err;
        u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
        bool ret;
 
@@ -1424,7 +1464,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
                        memcpy(ha_buf, neigh->ha, dev->addr_len);
                        read_unlock_bh(&neigh->lock);
                        ha = ha_buf;
-                       len += ndisc_opt_addr_space(dev);
+                       optlen += ndisc_opt_addr_space(dev);
                } else
                        read_unlock_bh(&neigh->lock);
 
@@ -1432,80 +1472,40 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
        }
 
        rd_len = min_t(unsigned int,
-                    IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
+                      IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
+                      skb->len + 8);
        rd_len &= ~0x7;
-       len += rd_len;
-
-       hlen = LL_RESERVED_SPACE(dev);
-       tlen = dev->needed_tailroom;
-       buff = sock_alloc_send_skb(sk,
-                                  (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                   len + hlen + tlen),
-                                  1, &err);
-       if (buff == NULL) {
-               ND_PRINTK(0, err,
-                         "Redirect: %s failed to allocate an skb, err=%d\n",
-                         __func__, err);
-               goto release;
-       }
-
-       skb_reserve(buff, hlen);
-       ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
-                  IPPROTO_ICMPV6, len);
-
-       skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
-       skb_put(buff, len);
-       icmph = icmp6_hdr(buff);
-
-       memset(icmph, 0, sizeof(struct icmp6hdr));
-       icmph->icmp6_type = NDISC_REDIRECT;
+       optlen += rd_len;
 
-       /*
-        *      copy target and destination addresses
-        */
-
-       addrp = (struct in6_addr *)(icmph + 1);
-       *addrp = *target;
-       addrp++;
-       *addrp = ipv6_hdr(skb)->daddr;
+       buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
+       if (!buff)
+               goto release;
 
-       opt = (u8*) (addrp + 1);
+       msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
+       *msg = (struct rd_msg) {
+               .icmph = {
+                       .icmp6_type = NDISC_REDIRECT,
+               },
+               .target = *target,
+               .dest = ipv6_hdr(skb)->daddr,
+       };
 
        /*
         *      include target_address option
         */
 
        if (ha)
-               opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
-                                            dev->addr_len, dev->type);
+               ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha);
 
        /*
         *      build redirect option and copy skb over to the new packet.
         */
 
-       memset(opt, 0, 8);
-       *(opt++) = ND_OPT_REDIRECT_HDR;
-       *(opt++) = (rd_len >> 3);
-       opt += 6;
-
-       memcpy(opt, ipv6_hdr(skb), rd_len - 8);
-
-       icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
-                                            len, IPPROTO_ICMPV6,
-                                            csum_partial(icmph, len, 0));
+       if (rd_len)
+               ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
 
        skb_dst_set(buff, dst);
-       rcu_read_lock();
-       idev = __in6_dev_get(dst->dev);
-       IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
-       err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
-                     dst_output);
-       if (!err) {
-               ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
-               ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
-       }
-
-       rcu_read_unlock();
+       ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
        return;
 
 release:
@@ -1522,7 +1522,7 @@ int ndisc_rcv(struct sk_buff *skb)
 {
        struct nd_msg *msg;
 
-       if (!pskb_may_pull(skb, skb->len))
+       if (skb_linearize(skb))
                return 0;
 
        msg = (struct nd_msg *)skb_transport_header(skb);
index 125a90d6a795967f13fcdfd19b3c24e24ce02504..341b54ade72cd045472e5957c33370c84d3338b0 100644 (file)
@@ -1098,7 +1098,7 @@ static int get_info(struct net *net, void __user *user,
 #endif
        t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
                                    "ip6table_%s", name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                struct ip6t_getinfo info;
                const struct xt_table_info *private = t->private;
 #ifdef CONFIG_COMPAT
@@ -1157,7 +1157,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
        }
 
        t = xt_find_table_lock(net, AF_INET6, get.name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n", private->number);
                if (get.size == private->size)
@@ -1197,7 +1197,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
 
        t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
                                    "ip6table_%s", name);
-       if (!t || IS_ERR(t)) {
+       if (IS_ERR_OR_NULL(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free_newinfo_counters_untrans;
        }
@@ -1355,7 +1355,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
        }
 
        t = xt_find_table_lock(net, AF_INET6, name);
-       if (!t || IS_ERR(t)) {
+       if (IS_ERR_OR_NULL(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
        }
@@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
 
        xt_compat_lock(AF_INET6);
        t = xt_find_table_lock(net, AF_INET6, get.name);
-       if (t && !IS_ERR(t)) {
+       if (!IS_ERR_OR_NULL(t)) {
                const struct xt_table_info *private = t->private;
                struct xt_table_info info;
                duprintf("t->private->number = %u\n", private->number);
index 029623dbd4118d18667a83d209131dc64b5ec7c4..ed3b427b284142c037d66d63ee3fa7e205925708 100644 (file)
@@ -126,7 +126,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
        skb_put(nskb, sizeof(struct ipv6hdr));
        skb_reset_network_header(nskb);
        ip6h = ipv6_hdr(nskb);
-       *(__be32 *)ip6h =  htonl(0x60000000 | (tclass << 20));
+       ip6_flow_hdr(ip6h, tclass, 0);
        ip6h->hop_limit = ip6_dst_hoplimit(dst);
        ip6h->nexthdr = IPPROTO_TCP;
        ip6h->saddr = oip6h->daddr;
index 137e245860ab41a9ec923a8655f538c8cc8d4e52..8a45bb20bedb49674fbb024a3dfb90ea5c54298c 100644 (file)
@@ -421,54 +421,43 @@ static int ipv6_net_init(struct net *net)
 {
        int ret = 0;
 
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_tcp6);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp6);
        if (ret < 0) {
-               printk(KERN_ERR "nf_conntrack_l4proto_tcp6: protocol register failed\n");
+               pr_err("nf_conntrack_tcp6: pernet registration failed\n");
                goto out;
        }
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_udp6);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp6);
        if (ret < 0) {
-               printk(KERN_ERR "nf_conntrack_l4proto_udp6: protocol register failed\n");
+               pr_err("nf_conntrack_udp6: pernet registration failed\n");
                goto cleanup_tcp6;
        }
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_icmpv6);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmpv6);
        if (ret < 0) {
-               printk(KERN_ERR "nf_conntrack_l4proto_icmp6: protocol register failed\n");
+               pr_err("nf_conntrack_icmp6: pernet registration failed\n");
                goto cleanup_udp6;
        }
-       ret = nf_conntrack_l3proto_register(net,
-                                           &nf_conntrack_l3proto_ipv6);
+       ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv6);
        if (ret < 0) {
-               printk(KERN_ERR "nf_conntrack_l3proto_ipv6: protocol register failed\n");
+               pr_err("nf_conntrack_ipv6: pernet registration failed.\n");
                goto cleanup_icmpv6;
        }
        return 0;
  cleanup_icmpv6:
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_icmpv6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
  cleanup_udp6:
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_udp6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
  cleanup_tcp6:
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_tcp6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6);
  out:
        return ret;
 }
 
 static void ipv6_net_exit(struct net *net)
 {
-       nf_conntrack_l3proto_unregister(net,
-                                       &nf_conntrack_l3proto_ipv6);
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_icmpv6);
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_udp6);
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_tcp6);
+       nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6);
 }
 
 static struct pernet_operations ipv6_net_ops = {
@@ -491,19 +480,52 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 
        ret = register_pernet_subsys(&ipv6_net_ops);
        if (ret < 0)
-               goto cleanup_pernet;
+               goto cleanup_sockopt;
+
        ret = nf_register_hooks(ipv6_conntrack_ops,
                                ARRAY_SIZE(ipv6_conntrack_ops));
        if (ret < 0) {
                pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
                       "hook.\n");
-               goto cleanup_ipv6;
+               goto cleanup_pernet;
+       }
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n");
+               goto cleanup_hooks;
+       }
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv6: can't register udp6 proto.\n");
+               goto cleanup_tcp6;
+       }
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmpv6);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv6: can't register icmpv6 proto.\n");
+               goto cleanup_udp6;
+       }
+
+       ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6);
+       if (ret < 0) {
+               pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n");
+               goto cleanup_icmpv6;
        }
        return ret;
 
- cleanup_ipv6:
-       unregister_pernet_subsys(&ipv6_net_ops);
+ cleanup_icmpv6:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
+ cleanup_udp6:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6);
+ cleanup_tcp6:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
+ cleanup_hooks:
+       nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
  cleanup_pernet:
+       unregister_pernet_subsys(&ipv6_net_ops);
+ cleanup_sockopt:
        nf_unregister_sockopt(&so_getorigdst6);
        return ret;
 }
@@ -511,6 +533,10 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 static void __exit nf_conntrack_l3proto_ipv6_fini(void)
 {
        synchronize_net();
+       nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
        nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
        unregister_pernet_subsys(&ipv6_net_ops);
        nf_unregister_sockopt(&so_getorigdst6);
index 3dacecc9906597e3f44fa9475dda0afb8f4981c2..c674f158efa8bedfcda37e4e66c5f8e7deb79202 100644 (file)
@@ -319,7 +319,7 @@ found:
        fq->q.meat += skb->len;
        if (payload_len > fq->q.max_size)
                fq->q.max_size = payload_len;
-       atomic_add(skb->truesize, &fq->q.net->mem);
+       add_frag_mem_limit(&fq->q, skb->truesize);
 
        /* The first fragment.
         * nhoffset is obtained from the first fragment, of course.
@@ -328,9 +328,8 @@ found:
                fq->nhoffset = nhoff;
                fq->q.last_in |= INET_FRAG_FIRST_IN;
        }
-       write_lock(&nf_frags.lock);
-       list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list);
-       write_unlock(&nf_frags.lock);
+
+       inet_frag_lru_move(&fq->q);
        return 0;
 
 discard_fq:
@@ -398,7 +397,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
                clone->ip_summed = head->ip_summed;
 
                NFCT_FRAG6_CB(clone)->orig = NULL;
-               atomic_add(clone->truesize, &fq->q.net->mem);
+               add_frag_mem_limit(&fq->q, clone->truesize);
        }
 
        /* We have to remove fragment header from datagram and to relocate
@@ -422,7 +421,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
                        head->csum = csum_add(head->csum, fp->csum);
                head->truesize += fp->truesize;
        }
-       atomic_sub(head->truesize, &fq->q.net->mem);
+       sub_frag_mem_limit(&fq->q, head->truesize);
 
        head->local_df = 1;
        head->next = NULL;
index e5253ec9e0fcd8b80e506956e68b29407b0be3c6..bab2c270f29207c37ed7b107b6d25c6e12a6053d 100644 (file)
@@ -327,7 +327,7 @@ found:
        }
        fq->q.stamp = skb->tstamp;
        fq->q.meat += skb->len;
-       atomic_add(skb->truesize, &fq->q.net->mem);
+       add_frag_mem_limit(&fq->q, skb->truesize);
 
        /* The first fragment.
         * nhoffset is obtained from the first fragment, of course.
@@ -341,9 +341,7 @@ found:
            fq->q.meat == fq->q.len)
                return ip6_frag_reasm(fq, prev, dev);
 
-       write_lock(&ip6_frags.lock);
-       list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list);
-       write_unlock(&ip6_frags.lock);
+       inet_frag_lru_move(&fq->q);
        return -1;
 
 discard_fq:
@@ -429,7 +427,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               atomic_add(clone->truesize, &fq->q.net->mem);
+               add_frag_mem_limit(&fq->q, clone->truesize);
        }
 
        /* We have to remove fragment header from datagram and to relocate
@@ -467,7 +465,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                }
                fp = next;
        }
-       atomic_sub(sum_truesize, &fq->q.net->mem);
+       sub_frag_mem_limit(&fq->q, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
index e229a3bc345dc4138a188282c4ab4f1717882832..f3328bc1174f0d3d7825c17bc76e4ae9b5c0a9f2 100644 (file)
@@ -145,25 +145,12 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
        struct neighbour *n;
 
        daddr = choose_neigh_daddr(rt, skb, daddr);
-       n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr);
+       n = __ipv6_neigh_lookup(dst->dev, daddr);
        if (n)
                return n;
        return neigh_create(&nd_tbl, daddr, dst->dev);
 }
 
-static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev)
-{
-       struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dev, &rt->rt6i_gateway);
-       if (!n) {
-               n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev);
-               if (IS_ERR(n))
-                       return PTR_ERR(n);
-       }
-       rt->n = n;
-
-       return 0;
-}
-
 static struct dst_ops ip6_dst_ops_template = {
        .family                 =       AF_INET6,
        .protocol               =       cpu_to_be16(ETH_P_IPV6),
@@ -301,9 +288,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
        struct rt6_info *rt = (struct rt6_info *)dst;
        struct inet6_dev *idev = rt->rt6i_idev;
 
-       if (rt->n)
-               neigh_release(rt->n);
-
        if (!(rt->dst.flags & DST_HOST))
                dst_destroy_metrics_generic(dst);
 
@@ -354,11 +338,6 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
                                in6_dev_put(idev);
                        }
                }
-               if (rt->n && rt->n->dev == dev) {
-                       rt->n->dev = loopback_dev;
-                       dev_hold(loopback_dev);
-                       dev_put(dev);
-               }
        }
 }
 
@@ -388,15 +367,8 @@ static int rt6_info_hash_nhsfn(unsigned int candidate_count,
 {
        unsigned int val = fl6->flowi6_proto;
 
-       val ^= (__force u32)fl6->daddr.s6_addr32[0];
-       val ^= (__force u32)fl6->daddr.s6_addr32[1];
-       val ^= (__force u32)fl6->daddr.s6_addr32[2];
-       val ^= (__force u32)fl6->daddr.s6_addr32[3];
-
-       val ^= (__force u32)fl6->saddr.s6_addr32[0];
-       val ^= (__force u32)fl6->saddr.s6_addr32[1];
-       val ^= (__force u32)fl6->saddr.s6_addr32[2];
-       val ^= (__force u32)fl6->saddr.s6_addr32[3];
+       val ^= ipv6_addr_hash(&fl6->daddr);
+       val ^= ipv6_addr_hash(&fl6->saddr);
 
        /* Work only if this not encapsulated */
        switch (fl6->flowi6_proto) {
@@ -505,24 +477,34 @@ static void rt6_probe(struct rt6_info *rt)
         * Router Reachability Probe MUST be rate-limited
         * to no more than one per minute.
         */
-       neigh = rt ? rt->n : NULL;
-       if (!neigh || (neigh->nud_state & NUD_VALID))
+       if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
                return;
-       read_lock_bh(&neigh->lock);
-       if (!(neigh->nud_state & NUD_VALID) &&
+       rcu_read_lock_bh();
+       neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
+       if (neigh) {
+               write_lock(&neigh->lock);
+               if (neigh->nud_state & NUD_VALID)
+                       goto out;
+       }
+
+       if (!neigh ||
            time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
                struct in6_addr mcaddr;
                struct in6_addr *target;
 
-               neigh->updated = jiffies;
-               read_unlock_bh(&neigh->lock);
+               if (neigh) {
+                       neigh->updated = jiffies;
+                       write_unlock(&neigh->lock);
+               }
 
-               target = (struct in6_addr *)&neigh->primary_key;
+               target = (struct in6_addr *)&rt->rt6i_gateway;
                addrconf_addr_solict_mult(target, &mcaddr);
                ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
        } else {
-               read_unlock_bh(&neigh->lock);
+out:
+               write_unlock(&neigh->lock);
        }
+       rcu_read_unlock_bh();
 }
 #else
 static inline void rt6_probe(struct rt6_info *rt)
@@ -549,20 +531,24 @@ static inline bool rt6_check_neigh(struct rt6_info *rt)
        struct neighbour *neigh;
        bool ret = false;
 
-       neigh = rt->n;
        if (rt->rt6i_flags & RTF_NONEXTHOP ||
            !(rt->rt6i_flags & RTF_GATEWAY))
-               ret = true;
-       else if (neigh) {
-               read_lock_bh(&neigh->lock);
+               return true;
+
+       rcu_read_lock_bh();
+       neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
+       if (neigh) {
+               read_lock(&neigh->lock);
                if (neigh->nud_state & NUD_VALID)
                        ret = true;
 #ifdef CONFIG_IPV6_ROUTER_PREF
                else if (!(neigh->nud_state & NUD_FAILED))
                        ret = true;
 #endif
-               read_unlock_bh(&neigh->lock);
+               read_unlock(&neigh->lock);
        }
+       rcu_read_unlock_bh();
+
        return ret;
 }
 
@@ -838,8 +824,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
        rt = ip6_rt_copy(ort, daddr);
 
        if (rt) {
-               int attempts = !in_softirq();
-
                if (!(rt->rt6i_flags & RTF_GATEWAY)) {
                        if (ort->rt6i_dst.plen != 128 &&
                            ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
@@ -855,32 +839,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
                        rt->rt6i_src.plen = 128;
                }
 #endif
-
-       retry:
-               if (rt6_bind_neighbour(rt, rt->dst.dev)) {
-                       struct net *net = dev_net(rt->dst.dev);
-                       int saved_rt_min_interval =
-                               net->ipv6.sysctl.ip6_rt_gc_min_interval;
-                       int saved_rt_elasticity =
-                               net->ipv6.sysctl.ip6_rt_gc_elasticity;
-
-                       if (attempts-- > 0) {
-                               net->ipv6.sysctl.ip6_rt_gc_elasticity = 1;
-                               net->ipv6.sysctl.ip6_rt_gc_min_interval = 0;
-
-                               ip6_dst_gc(&net->ipv6.ip6_dst_ops);
-
-                               net->ipv6.sysctl.ip6_rt_gc_elasticity =
-                                       saved_rt_elasticity;
-                               net->ipv6.sysctl.ip6_rt_gc_min_interval =
-                                       saved_rt_min_interval;
-                               goto retry;
-                       }
-
-                       net_warn_ratelimited("Neighbour table overflow\n");
-                       dst_free(&rt->dst);
-                       return NULL;
-               }
        }
 
        return rt;
@@ -891,10 +849,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
 {
        struct rt6_info *rt = ip6_rt_copy(ort, daddr);
 
-       if (rt) {
+       if (rt)
                rt->rt6i_flags |= RTF_CACHE;
-               rt->n = neigh_clone(ort->n);
-       }
        return rt;
 }
 
@@ -928,7 +884,7 @@ restart:
        dst_hold(&rt->dst);
        read_unlock_bh(&table->tb6_lock);
 
-       if (!rt->n && !(rt->rt6i_flags & RTF_NONEXTHOP))
+       if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)))
                nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
        else if (!(rt->dst.flags & DST_HOST))
                nrt = rt6_alloc_clone(rt, &fl6->daddr);
@@ -994,7 +950,7 @@ void ip6_route_input(struct sk_buff *skb)
                .flowi6_iif = skb->dev->ifindex,
                .daddr = iph->daddr,
                .saddr = iph->saddr,
-               .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
+               .flowlabel = ip6_flowinfo(iph),
                .flowi6_mark = skb->mark,
                .flowi6_proto = iph->nexthdr,
        };
@@ -1159,7 +1115,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
        fl6.flowi6_flags = 0;
        fl6.daddr = iph->daddr;
        fl6.saddr = iph->saddr;
-       fl6.flowlabel = (*(__be32 *) iph) & IPV6_FLOWINFO_MASK;
+       fl6.flowlabel = ip6_flowinfo(iph);
 
        dst = ip6_route_output(net, NULL, &fl6);
        if (!dst->error)
@@ -1187,7 +1143,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
        fl6.flowi6_flags = 0;
        fl6.daddr = iph->daddr;
        fl6.saddr = iph->saddr;
-       fl6.flowlabel = (*(__be32 *) iph) & IPV6_FLOWINFO_MASK;
+       fl6.flowlabel = ip6_flowinfo(iph);
 
        dst = ip6_route_output(net, NULL, &fl6);
        if (!dst->error)
@@ -1247,7 +1203,6 @@ static struct dst_entry *icmp6_dst_gc_list;
 static DEFINE_SPINLOCK(icmp6_dst_lock);
 
 struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
-                                 struct neighbour *neigh,
                                  struct flowi6 *fl6)
 {
        struct dst_entry *dst;
@@ -1265,20 +1220,8 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
                goto out;
        }
 
-       if (neigh)
-               neigh_hold(neigh);
-       else {
-               neigh = ip6_neigh_lookup(&rt->dst, NULL, &fl6->daddr);
-               if (IS_ERR(neigh)) {
-                       in6_dev_put(idev);
-                       dst_free(&rt->dst);
-                       return ERR_CAST(neigh);
-               }
-       }
-
        rt->dst.flags |= DST_HOST;
        rt->dst.output  = ip6_output;
-       rt->n = neigh;
        atomic_set(&rt->dst.__refcnt, 1);
        rt->rt6i_dst.addr = fl6->daddr;
        rt->rt6i_dst.plen = 128;
@@ -1587,12 +1530,6 @@ int ip6_route_add(struct fib6_config *cfg)
        } else
                rt->rt6i_prefsrc.plen = 0;
 
-       if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
-               err = rt6_bind_neighbour(rt, dev);
-               if (err)
-                       goto out;
-       }
-
        rt->rt6i_flags = cfg->fc_flags;
 
 install_route:
@@ -1705,37 +1642,32 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
        struct net *net = dev_net(skb->dev);
        struct netevent_redirect netevent;
        struct rt6_info *rt, *nrt = NULL;
-       const struct in6_addr *target;
        struct ndisc_options ndopts;
-       const struct in6_addr *dest;
-       struct neighbour *old_neigh;
        struct inet6_dev *in6_dev;
        struct neighbour *neigh;
-       struct icmp6hdr *icmph;
+       struct rd_msg *msg;
        int optlen, on_link;
        u8 *lladdr;
 
        optlen = skb->tail - skb->transport_header;
-       optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+       optlen -= sizeof(*msg);
 
        if (optlen < 0) {
                net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
                return;
        }
 
-       icmph = icmp6_hdr(skb);
-       target = (const struct in6_addr *) (icmph + 1);
-       dest = target + 1;
+       msg = (struct rd_msg *)icmp6_hdr(skb);
 
-       if (ipv6_addr_is_multicast(dest)) {
+       if (ipv6_addr_is_multicast(&msg->dest)) {
                net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
                return;
        }
 
        on_link = 0;
-       if (ipv6_addr_equal(dest, target)) {
+       if (ipv6_addr_equal(&msg->dest, &msg->target)) {
                on_link = 1;
-       } else if (ipv6_addr_type(target) !=
+       } else if (ipv6_addr_type(&msg->target) !=
                   (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
                net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
                return;
@@ -1752,7 +1684,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
         *      first-hop router for the specified ICMP Destination Address.
         */
 
-       if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
+       if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
                net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
                return;
        }
@@ -1779,15 +1711,10 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
         */
        dst_confirm(&rt->dst);
 
-       neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
+       neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
        if (!neigh)
                return;
 
-       /* Duplicate redirect: silently ignore. */
-       old_neigh = rt->n;
-       if (neigh == old_neigh)
-               goto out;
-
        /*
         *      We have finally decided to accept it.
         */
@@ -1799,7 +1726,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
                                     NEIGH_UPDATE_F_ISROUTER))
                     );
 
-       nrt = ip6_rt_copy(rt, dest);
+       nrt = ip6_rt_copy(rt, &msg->dest);
        if (!nrt)
                goto out;
 
@@ -1808,16 +1735,14 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
                nrt->rt6i_flags &= ~RTF_GATEWAY;
 
        nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
-       nrt->n = neigh_clone(neigh);
 
        if (ip6_ins_rt(nrt))
                goto out;
 
        netevent.old = &rt->dst;
-       netevent.old_neigh = old_neigh;
        netevent.new = &nrt->dst;
-       netevent.new_neigh = neigh;
-       netevent.daddr = dest;
+       netevent.daddr = &msg->dest;
+       netevent.neigh = neigh;
        call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
 
        if (rt->rt6i_flags & RTF_CACHE) {
@@ -2123,7 +2048,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 {
        struct net *net = dev_net(idev->dev);
        struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
-       int err;
 
        if (!rt) {
                net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
@@ -2142,11 +2066,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
                rt->rt6i_flags |= RTF_ANYCAST;
        else
                rt->rt6i_flags |= RTF_LOCAL;
-       err = rt6_bind_neighbour(rt, rt->dst.dev);
-       if (err) {
-               dst_free(&rt->dst);
-               return ERR_PTR(err);
-       }
 
        rt->rt6i_dst.addr = *addr;
        rt->rt6i_dst.plen = 128;
@@ -2492,7 +2411,6 @@ static int rt6_fill_node(struct net *net,
        struct nlmsghdr *nlh;
        long expires;
        u32 table;
-       struct neighbour *n;
 
        if (prefix) {   /* user wants prefix routes only */
                if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
@@ -2605,9 +2523,8 @@ static int rt6_fill_node(struct net *net,
        if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
                goto nla_put_failure;
 
-       n = rt->n;
-       if (n) {
-               if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0)
+       if (rt->rt6i_flags & RTF_GATEWAY) {
+               if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0)
                        goto nla_put_failure;
        }
 
@@ -2802,7 +2719,6 @@ struct rt6_proc_arg
 static int rt6_info_route(struct rt6_info *rt, void *p_arg)
 {
        struct seq_file *m = p_arg;
-       struct neighbour *n;
 
        seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
 
@@ -2811,9 +2727,8 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)
 #else
        seq_puts(m, "00000000000000000000000000000000 00 ");
 #endif
-       n = rt->n;
-       if (n) {
-               seq_printf(m, "%pi6", n->primary_key);
+       if (rt->rt6i_flags & RTF_GATEWAY) {
+               seq_printf(m, "%pi6", &rt->rt6i_gateway);
        } else {
                seq_puts(m, "00000000000000000000000000000000");
        }
index cfba99b2c2a4958144ff4c2a2faa1d98192d7310..02f96dcbcf02a15639fdc359a5058a2650029454 100644 (file)
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
 static int ipip6_tunnel_init(struct net_device *dev);
 static void ipip6_tunnel_setup(struct net_device *dev);
 static void ipip6_dev_free(struct net_device *dev);
+static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst,
+                     __be32 *v4dst);
 static struct rtnl_link_ops sit_link_ops __read_mostly;
 
 static int sit_net_id __read_mostly;
@@ -590,17 +592,21 @@ out:
        return err;
 }
 
+static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr,
+                                 const struct in6_addr *v6addr)
+{
+       __be32 v4embed = 0;
+       if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed)
+               return true;
+       return false;
+}
+
 static int ipip6_rcv(struct sk_buff *skb)
 {
-       const struct iphdr *iph;
+       const struct iphdr *iph = ip_hdr(skb);
        struct ip_tunnel *tunnel;
        int err;
 
-       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
-               goto out;
-
-       iph = ip_hdr(skb);
-
        tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
                                     iph->saddr, iph->daddr);
        if (tunnel != NULL) {
@@ -613,10 +619,19 @@ static int ipip6_rcv(struct sk_buff *skb)
                skb->protocol = htons(ETH_P_IPV6);
                skb->pkt_type = PACKET_HOST;
 
-               if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
-                   !isatap_chksrc(skb, iph, tunnel)) {
-                       tunnel->dev->stats.rx_errors++;
-                       goto out;
+               if (tunnel->dev->priv_flags & IFF_ISATAP) {
+                       if (!isatap_chksrc(skb, iph, tunnel)) {
+                               tunnel->dev->stats.rx_errors++;
+                               goto out;
+                       }
+               } else {
+                       if (is_spoofed_6rd(tunnel, iph->saddr,
+                                          &ipv6_hdr(skb)->saddr) ||
+                           is_spoofed_6rd(tunnel, iph->daddr,
+                                          &ipv6_hdr(skb)->daddr)) {
+                               tunnel->dev->stats.rx_errors++;
+                               goto out;
+                       }
                }
 
                __skb_tunnel_rx(skb, tunnel->dev);
@@ -650,14 +665,12 @@ out:
 }
 
 /*
- * Returns the embedded IPv4 address if the IPv6 address
- * comes from 6rd / 6to4 (RFC 3056) addr space.
+ * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function
+ * stores the embedded IPv4 address in v4dst and returns true.
  */
-static inline
-__be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel)
+static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst,
+                     __be32 *v4dst)
 {
-       __be32 dst = 0;
-
 #ifdef CONFIG_IPV6_SIT_6RD
        if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
                              tunnel->ip6rd.prefixlen)) {
@@ -676,14 +689,24 @@ __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel)
                        d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >>
                             (32 - pbi1);
 
-               dst = tunnel->ip6rd.relay_prefix | htonl(d);
+               *v4dst = tunnel->ip6rd.relay_prefix | htonl(d);
+               return true;
        }
 #else
        if (v6dst->s6_addr16[0] == htons(0x2002)) {
                /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */
-               memcpy(&dst, &v6dst->s6_addr16[1], 4);
+               memcpy(v4dst, &v6dst->s6_addr16[1], 4);
+               return true;
        }
 #endif
+       return false;
+}
+
+static inline __be32 try_6rd(struct ip_tunnel *tunnel,
+                            const struct in6_addr *v6dst)
+{
+       __be32 dst = 0;
+       check_6rd(tunnel, v6dst, &dst);
        return dst;
 }
 
@@ -744,7 +767,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
        }
 
        if (!dst)
-               dst = try_6rd(&iph6->daddr, tunnel);
+               dst = try_6rd(tunnel, &iph6->daddr);
 
        if (!dst) {
                struct neighbour *neigh = NULL;
index 40161977f7cf0b69ecc488d87427e03c88d61598..8a0848b60b3539babdf245f4cf256761cfb704cd 100644 (file)
@@ -179,7 +179,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        memset(&tcp_opt, 0, sizeof(tcp_opt));
        tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
 
-       if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+       if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
                goto out;
 
        ret = NULL;
index 93825dd3a7c070be4dd1e294a155b409525337e2..06087e58738a553ce2ff050cb6bbbcac5d393014 100644 (file)
@@ -834,7 +834,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
                 * no RST generated if md5 hash doesn't match.
                 */
                sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
-                                          &tcp_hashinfo, &ipv6h->daddr,
+                                          &tcp_hashinfo, &ipv6h->saddr,
+                                          th->source, &ipv6h->daddr,
                                           ntohs(th->source), inet6_iif(skb));
                if (!sk1)
                        return;
@@ -1027,7 +1028,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        treq->rmt_addr = ipv6_hdr(skb)->saddr;
        treq->loc_addr = ipv6_hdr(skb)->daddr;
        if (!want_cookie || tmp_opt.tstamp_ok)
-               TCP_ECN_create_request(req, skb);
+               TCP_ECN_create_request(req, skb, sock_net(sk));
 
        treq->iif = sk->sk_bound_dev_if;
 
@@ -1163,7 +1164,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                newnp->opt         = NULL;
                newnp->mcast_oif   = inet6_iif(skb);
                newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
-               newnp->rcv_tclass  = ipv6_tclass(ipv6_hdr(skb));
+               newnp->rcv_tclass  = ipv6_get_dsfield(ipv6_hdr(skb));
 
                /*
                 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
@@ -1243,7 +1244,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newnp->opt        = NULL;
        newnp->mcast_oif  = inet6_iif(skb);
        newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
-       newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
+       newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb));
 
        /* Clone native IPv6 options from listening socket (if any)
 
@@ -1456,7 +1457,7 @@ ipv6_pktoptions:
                if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
                        np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
                if (np->rxopt.bits.rxtclass)
-                       np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
+                       np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb));
                if (ipv6_opt_accepted(sk, opt_skb)) {
                        skb_set_owner_r(opt_skb, sk);
                        opt_skb = xchg(&np->pktoptions, opt_skb);
@@ -1598,6 +1599,7 @@ do_time_wait:
                struct sock *sk2;
 
                sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
+                                           &ipv6_hdr(skb)->saddr, th->source,
                                            &ipv6_hdr(skb)->daddr,
                                            ntohs(th->dest), inet6_iif(skb));
                if (sk2 != NULL) {
index dfaa29b8b2939c03fef13fa416f6fdaef031bf5d..cb5bf497c09c4e1ebffa8d2c2ad84c9fca678a15 100644 (file)
@@ -45,6 +45,7 @@
 #include <net/tcp_states.h>
 #include <net/ip6_checksum.h>
 #include <net/xfrm.h>
+#include <net/inet6_hashtables.h>
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net,
 {
        struct sock *sk, *result;
        struct hlist_nulls_node *node;
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
 begin:
        result = NULL;
@@ -214,8 +216,18 @@ begin:
                if (score > badness) {
                        result = sk;
                        badness = score;
-                       if (score == SCORE2_MAX)
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet6_ehashfn(net, daddr, hnum,
+                                                    saddr, sport);
+                               matches = 1;
+                       } else if (score == SCORE2_MAX)
                                goto exact_match;
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net,
        unsigned short hnum = ntohs(dport);
        unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
        struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
        rcu_read_lock();
        if (hslot->count > 10) {
@@ -284,6 +297,17 @@ begin:
                if (score > badness) {
                        result = sk;
                        badness = score;
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet6_ehashfn(net, daddr, hnum,
+                                                    saddr, sport);
+                               matches = 1;
+                       }
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -752,40 +776,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
        return 0;
 }
 
-static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
-                                int proto)
-{
-       int err;
-
-       UDP_SKB_CB(skb)->partial_cov = 0;
-       UDP_SKB_CB(skb)->cscov = skb->len;
-
-       if (proto == IPPROTO_UDPLITE) {
-               err = udplite_checksum_init(skb, uh);
-               if (err)
-                       return err;
-       }
-
-       if (uh->check == 0) {
-               /* RFC 2460 section 8.1 says that we SHOULD log
-                  this error. Well, it is reasonable.
-                */
-               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
-               return 1;
-       }
-       if (skb->ip_summed == CHECKSUM_COMPLETE &&
-           !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
-                            skb->len, proto, skb->csum))
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-       if (!skb_csum_unnecessary(skb))
-               skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                        &ipv6_hdr(skb)->daddr,
-                                                        skb->len, proto, 0));
-
-       return 0;
-}
-
 int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                   int proto)
 {
index c9844135c9caea041bd9a680e39da7bba4cf0997..128273744332bef4f8d661bc559c8c8e5f0fb407 100644 (file)
@@ -110,7 +110,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 
        /* Sheit... I remember I did this right. Apparently,
         * it was magically lost, so this code needs audit */
-       xdst->u.rt6.n = neigh_clone(rt->n);
        xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
                                                   RTF_LOCAL);
        xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
index ee5a7065aaccec7fa690af1c72a5785b94e6d6aa..babd1674388a962b86c63fce58a79bdd7f27b522 100644 (file)
@@ -72,7 +72,7 @@ static inline unsigned int xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *ad
 {
        unsigned int h;
 
-       h = (__force u32)(addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]);
+       h = ipv6_addr_hash((const struct in6_addr *)addr);
        h ^= h >> 16;
        h ^= h >> 8;
        h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1;
index 2bb2beb6a373d8b58ff9d112cae385e32093c94e..3c83a1e5ab0394f0eaa04b4ba5a813d118c17434 100644 (file)
@@ -214,8 +214,7 @@ irnet_get_discovery_log(irnet_socket *      ap)
  * After reading :    discoveries = NULL ; disco_index = Y ; disco_number = -1
  */
 static inline int
-irnet_read_discovery_log(irnet_socket *        ap,
-                        char *         event)
+irnet_read_discovery_log(irnet_socket *ap, char *event, int buf_size)
 {
   int          done_event = 0;
 
@@ -237,12 +236,13 @@ irnet_read_discovery_log(irnet_socket *   ap,
   if(ap->disco_index < ap->disco_number)
     {
       /* Write an event */
-      sprintf(event, "Found %08x (%s) behind %08x {hints %02X-%02X}\n",
-             ap->discoveries[ap->disco_index].daddr,
-             ap->discoveries[ap->disco_index].info,
-             ap->discoveries[ap->disco_index].saddr,
-             ap->discoveries[ap->disco_index].hints[0],
-             ap->discoveries[ap->disco_index].hints[1]);
+      snprintf(event, buf_size,
+              "Found %08x (%s) behind %08x {hints %02X-%02X}\n",
+              ap->discoveries[ap->disco_index].daddr,
+              ap->discoveries[ap->disco_index].info,
+              ap->discoveries[ap->disco_index].saddr,
+              ap->discoveries[ap->disco_index].hints[0],
+              ap->discoveries[ap->disco_index].hints[1]);
       DEBUG(CTRL_INFO, "Writing discovery %d : %s\n",
            ap->disco_index, ap->discoveries[ap->disco_index].info);
 
@@ -282,27 +282,24 @@ irnet_ctrl_read(irnet_socket *    ap,
                size_t          count)
 {
   DECLARE_WAITQUEUE(wait, current);
-  char         event[64];      /* Max event is 61 char */
+  char         event[75];
   ssize_t      ret = 0;
 
   DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count);
 
-  /* Check if we can write an event out in one go */
-  DABORT(count < sizeof(event), -EOVERFLOW, CTRL_ERROR, "Buffer to small.\n");
-
 #ifdef INITIAL_DISCOVERY
   /* Check if we have read the log */
-  if(irnet_read_discovery_log(ap, event))
+  if (irnet_read_discovery_log(ap, event, sizeof(event)))
     {
-      /* We have an event !!! Copy it to the user */
-      if(copy_to_user(buf, event, strlen(event)))
+      count = min(strlen(event), count);
+      if (copy_to_user(buf, event, count))
        {
          DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
          return -EFAULT;
        }
 
       DEXIT(CTRL_TRACE, "\n");
-      return strlen(event);
+      return count;
     }
 #endif /* INITIAL_DISCOVERY */
 
@@ -339,79 +336,81 @@ irnet_ctrl_read(irnet_socket *    ap,
   switch(irnet_events.log[ap->event_index].event)
     {
     case IRNET_DISCOVER:
-      sprintf(event, "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].saddr,
-             irnet_events.log[ap->event_index].hints.byte[0],
-             irnet_events.log[ap->event_index].hints.byte[1]);
+      snprintf(event, sizeof(event),
+              "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].saddr,
+              irnet_events.log[ap->event_index].hints.byte[0],
+              irnet_events.log[ap->event_index].hints.byte[1]);
       break;
     case IRNET_EXPIRE:
-      sprintf(event, "Expired %08x (%s) behind %08x {hints %02X-%02X}\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].saddr,
-             irnet_events.log[ap->event_index].hints.byte[0],
-             irnet_events.log[ap->event_index].hints.byte[1]);
+      snprintf(event, sizeof(event),
+              "Expired %08x (%s) behind %08x {hints %02X-%02X}\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].saddr,
+              irnet_events.log[ap->event_index].hints.byte[0],
+              irnet_events.log[ap->event_index].hints.byte[1]);
       break;
     case IRNET_CONNECT_TO:
-      sprintf(event, "Connected to %08x (%s) on ppp%d\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].unit);
+      snprintf(event, sizeof(event), "Connected to %08x (%s) on ppp%d\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_CONNECT_FROM:
-      sprintf(event, "Connection from %08x (%s) on ppp%d\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].unit);
+      snprintf(event, sizeof(event), "Connection from %08x (%s) on ppp%d\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_REQUEST_FROM:
-      sprintf(event, "Request from %08x (%s) behind %08x\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].saddr);
+      snprintf(event, sizeof(event), "Request from %08x (%s) behind %08x\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].saddr);
       break;
     case IRNET_NOANSWER_FROM:
-      sprintf(event, "No-answer from %08x (%s) on ppp%d\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].unit);
+      snprintf(event, sizeof(event), "No-answer from %08x (%s) on ppp%d\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_BLOCKED_LINK:
-      sprintf(event, "Blocked link with %08x (%s) on ppp%d\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].unit);
+      snprintf(event, sizeof(event), "Blocked link with %08x (%s) on ppp%d\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_DISCONNECT_FROM:
-      sprintf(event, "Disconnection from %08x (%s) on ppp%d\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name,
-             irnet_events.log[ap->event_index].unit);
+      snprintf(event, sizeof(event), "Disconnection from %08x (%s) on ppp%d\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name,
+              irnet_events.log[ap->event_index].unit);
       break;
     case IRNET_DISCONNECT_TO:
-      sprintf(event, "Disconnected to %08x (%s)\n",
-             irnet_events.log[ap->event_index].daddr,
-             irnet_events.log[ap->event_index].name);
+      snprintf(event, sizeof(event), "Disconnected to %08x (%s)\n",
+              irnet_events.log[ap->event_index].daddr,
+              irnet_events.log[ap->event_index].name);
       break;
     default:
-      sprintf(event, "Bug\n");
+      snprintf(event, sizeof(event), "Bug\n");
     }
   /* Increment our event index */
   ap->event_index = (ap->event_index + 1) % IRNET_MAX_EVENTS;
 
   DEBUG(CTRL_INFO, "Event is :%s", event);
 
-  /* Copy it to the user */
-  if(copy_to_user(buf, event, strlen(event)))
+  count = min(strlen(event), count);
+  if (copy_to_user(buf, event, count))
     {
       DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
       return -EFAULT;
     }
 
   DEXIT(CTRL_TRACE, "\n");
-  return strlen(event);
+  return count;
 }
 
 /*------------------------------------------------------------------*/
index eb9df22418f08106241c51e6646b3c3d25c2f128..2f0ccbc5f13e82ee104ccd40b48cf9391162fbb3 100644 (file)
@@ -149,16 +149,133 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
        rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
 }
 
+static inline int ieee80211_ac_from_tid(int tid)
+{
+       return ieee802_1d_to_ac[tid & 7];
+}
+
+/*
+ * When multiple aggregation sessions on multiple stations
+ * are being created/destroyed simultaneously, we need to
+ * refcount the global queue stop caused by that in order
+ * to not get into a situation where one of the aggregation
+ * setup or teardown re-enables queues before the other is
+ * ready to handle that.
+ *
+ * These two functions take care of this issue by keeping
+ * a global "agg_queue_stop" refcount.
+ */
+static void __acquires(agg_queue)
+ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
+{
+       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
+
+       if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
+               ieee80211_stop_queue_by_reason(
+                       &sdata->local->hw, queue,
+                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+       __acquire(agg_queue);
+}
+
+static void __releases(agg_queue)
+ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
+{
+       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
+
+       if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
+               ieee80211_wake_queue_by_reason(
+                       &sdata->local->hw, queue,
+                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+       __release(agg_queue);
+}
+
+/*
+ * splice packets from the STA's pending to the local pending,
+ * requires a call to ieee80211_agg_splice_finish later
+ */
+static void __acquires(agg_queue)
+ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
+                            struct tid_ampdu_tx *tid_tx, u16 tid)
+{
+       struct ieee80211_local *local = sdata->local;
+       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
+       unsigned long flags;
+
+       ieee80211_stop_queue_agg(sdata, tid);
+
+       if (WARN(!tid_tx,
+                "TID %d gone but expected when splicing aggregates from the pending queue\n",
+                tid))
+               return;
+
+       if (!skb_queue_empty(&tid_tx->pending)) {
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               /* copy over remaining packets */
+               skb_queue_splice_tail_init(&tid_tx->pending,
+                                          &local->pending[queue]);
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+       }
+}
+
+static void __releases(agg_queue)
+ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
+{
+       ieee80211_wake_queue_agg(sdata, tid);
+}
+
+static void ieee80211_remove_tid_tx(struct sta_info *sta, int tid)
+{
+       struct tid_ampdu_tx *tid_tx;
+
+       lockdep_assert_held(&sta->ampdu_mlme.mtx);
+       lockdep_assert_held(&sta->lock);
+
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+
+       /*
+        * When we get here, the TX path will not be lockless any more wrt.
+        * aggregation, since the OPERATIONAL bit has long been cleared.
+        * Thus it will block on getting the lock, if it occurs. So if we
+        * stop the queue now, we will not get any more packets, and any
+        * that might be being processed will wait for us here, thereby
+        * guaranteeing that no packets go to the tid_tx pending queue any
+        * more.
+        */
+
+       ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
+
+       /* future packets must not find the tid_tx struct any more */
+       ieee80211_assign_tid_tx(sta, tid, NULL);
+
+       ieee80211_agg_splice_finish(sta->sdata, tid);
+
+       kfree_rcu(tid_tx, rcu_head);
+}
+
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                   enum ieee80211_back_parties initiator,
-                                   bool tx)
+                                   enum ieee80211_agg_stop_reason reason)
 {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_tx *tid_tx;
+       enum ieee80211_ampdu_mlme_action action;
        int ret;
 
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
+       switch (reason) {
+       case AGG_STOP_DECLINED:
+       case AGG_STOP_LOCAL_REQUEST:
+       case AGG_STOP_PEER_REQUEST:
+               action = IEEE80211_AMPDU_TX_STOP_CONT;
+               break;
+       case AGG_STOP_DESTROY_STA:
+               action = IEEE80211_AMPDU_TX_STOP_FLUSH;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+
        spin_lock_bh(&sta->lock);
 
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
@@ -167,10 +284,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                return -ENOENT;
        }
 
-       /* if we're already stopping ignore any new requests to stop */
+       /*
+        * if we're already stopping ignore any new requests to stop
+        * unless we're destroying it in which case notify the driver
+        */
        if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
                spin_unlock_bh(&sta->lock);
-               return -EALREADY;
+               if (reason != AGG_STOP_DESTROY_STA)
+                       return -EALREADY;
+               ret = drv_ampdu_action(local, sta->sdata,
+                                      IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
+                                      &sta->sta, tid, NULL, 0);
+               WARN_ON_ONCE(ret);
+               goto remove_tid_tx;
        }
 
        if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
@@ -212,11 +338,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
         */
        synchronize_net();
 
-       tid_tx->stop_initiator = initiator;
-       tid_tx->tx_stop = tx;
+       tid_tx->stop_initiator = reason == AGG_STOP_PEER_REQUEST ?
+                                       WLAN_BACK_RECIPIENT :
+                                       WLAN_BACK_INITIATOR;
+       tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
 
-       ret = drv_ampdu_action(local, sta->sdata,
-                              IEEE80211_AMPDU_TX_STOP,
+       ret = drv_ampdu_action(local, sta->sdata, action,
                               &sta->sta, tid, NULL, 0);
 
        /* HW shall not deny going back to legacy */
@@ -227,7 +354,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                 */
        }
 
-       return ret;
+       if (reason == AGG_STOP_DESTROY_STA) {
+ remove_tid_tx:
+               spin_lock_bh(&sta->lock);
+               ieee80211_remove_tid_tx(sta, tid);
+               spin_unlock_bh(&sta->lock);
+       }
+
+       return 0;
 }
 
 /*
@@ -264,80 +398,6 @@ static void sta_addba_resp_timer_expired(unsigned long data)
        rcu_read_unlock();
 }
 
-static inline int ieee80211_ac_from_tid(int tid)
-{
-       return ieee802_1d_to_ac[tid & 7];
-}
-
-/*
- * When multiple aggregation sessions on multiple stations
- * are being created/destroyed simultaneously, we need to
- * refcount the global queue stop caused by that in order
- * to not get into a situation where one of the aggregation
- * setup or teardown re-enables queues before the other is
- * ready to handle that.
- *
- * These two functions take care of this issue by keeping
- * a global "agg_queue_stop" refcount.
- */
-static void __acquires(agg_queue)
-ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
-{
-       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
-
-       if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
-               ieee80211_stop_queue_by_reason(
-                       &sdata->local->hw, queue,
-                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-       __acquire(agg_queue);
-}
-
-static void __releases(agg_queue)
-ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
-{
-       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
-
-       if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
-               ieee80211_wake_queue_by_reason(
-                       &sdata->local->hw, queue,
-                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-       __release(agg_queue);
-}
-
-/*
- * splice packets from the STA's pending to the local pending,
- * requires a call to ieee80211_agg_splice_finish later
- */
-static void __acquires(agg_queue)
-ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
-                            struct tid_ampdu_tx *tid_tx, u16 tid)
-{
-       struct ieee80211_local *local = sdata->local;
-       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
-       unsigned long flags;
-
-       ieee80211_stop_queue_agg(sdata, tid);
-
-       if (WARN(!tid_tx,
-                "TID %d gone but expected when splicing aggregates from the pending queue\n",
-                tid))
-               return;
-
-       if (!skb_queue_empty(&tid_tx->pending)) {
-               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-               /* copy over remaining packets */
-               skb_queue_splice_tail_init(&tid_tx->pending,
-                                          &local->pending[queue]);
-               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-       }
-}
-
-static void __releases(agg_queue)
-ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
-{
-       ieee80211_wake_queue_agg(sdata, tid);
-}
-
 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 {
        struct tid_ampdu_tx *tid_tx;
@@ -660,14 +720,13 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
 
 int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                  enum ieee80211_back_parties initiator,
-                                  bool tx)
+                                  enum ieee80211_agg_stop_reason reason)
 {
        int ret;
 
        mutex_lock(&sta->ampdu_mlme.mtx);
 
-       ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx);
+       ret = ___ieee80211_stop_tx_ba_session(sta, tid, reason);
 
        mutex_unlock(&sta->ampdu_mlme.mtx);
 
@@ -751,24 +810,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
                ieee80211_send_delba(sta->sdata, ra, tid,
                        WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
 
-       /*
-        * When we get here, the TX path will not be lockless any more wrt.
-        * aggregation, since the OPERATIONAL bit has long been cleared.
-        * Thus it will block on getting the lock, if it occurs. So if we
-        * stop the queue now, we will not get any more packets, and any
-        * that might be being processed will wait for us here, thereby
-        * guaranteeing that no packets go to the tid_tx pending queue any
-        * more.
-        */
-
-       ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
-
-       /* future packets must not find the tid_tx struct any more */
-       ieee80211_assign_tid_tx(sta, tid, NULL);
-
-       ieee80211_agg_splice_finish(sta->sdata, tid);
-
-       kfree_rcu(tid_tx, rcu_head);
+       ieee80211_remove_tid_tx(sta, tid);
 
  unlock_sta:
        spin_unlock_bh(&sta->lock);
@@ -868,8 +910,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
                }
 
        } else {
-               ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
-                                               false);
+               ___ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_DECLINED);
        }
 
  out:
index 516fbc96feff11831a9ad308541e6bdc16a7089d..661b878bd19ce979f0bcbed3693198ae53dd8b3e 100644 (file)
@@ -520,6 +520,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                                BIT(NL80211_STA_FLAG_WME) |
                                BIT(NL80211_STA_FLAG_MFP) |
                                BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                               BIT(NL80211_STA_FLAG_ASSOCIATED) |
                                BIT(NL80211_STA_FLAG_TDLS_PEER);
        if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
@@ -531,6 +532,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
        if (test_sta_flag(sta, WLAN_STA_AUTH))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+       if (test_sta_flag(sta, WLAN_STA_ASSOC))
+               sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
        if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
 }
@@ -940,6 +943,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
 
        sdata->vif.bss_conf.beacon_int = params->beacon_interval;
        sdata->vif.bss_conf.dtim_period = params->dtim_period;
+       sdata->vif.bss_conf.enable_beacon = true;
 
        sdata->vif.bss_conf.ssid_len = params->ssid_len;
        if (params->ssid_len)
@@ -1020,8 +1024,15 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
                kfree_rcu(old_probe_resp, rcu_head);
 
        list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
-               sta_info_flush(local, vlan);
-       sta_info_flush(local, sdata);
+               sta_info_flush_defer(vlan);
+       sta_info_flush_defer(sdata);
+       rcu_barrier();
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+               sta_info_flush_cleanup(vlan);
+       sta_info_flush_cleanup(sdata);
+
+       sdata->vif.bss_conf.enable_beacon = false;
+       clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
        drv_stop_ap(sdata->local, sdata);
@@ -1079,6 +1090,58 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
        netif_rx_ni(skb);
 }
 
+static int sta_apply_auth_flags(struct ieee80211_local *local,
+                               struct sta_info *sta,
+                               u32 mask, u32 set)
+{
+       int ret;
+
+       if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
+           set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
+           !test_sta_flag(sta, WLAN_STA_AUTH)) {
+               ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
+               if (ret)
+                       return ret;
+       }
+
+       if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
+           set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
+           !test_sta_flag(sta, WLAN_STA_ASSOC)) {
+               ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+               if (ret)
+                       return ret;
+       }
+
+       if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
+               if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
+                       ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+               else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+                       ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+               else
+                       ret = 0;
+               if (ret)
+                       return ret;
+       }
+
+       if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
+           !(set & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
+           test_sta_flag(sta, WLAN_STA_ASSOC)) {
+               ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
+               if (ret)
+                       return ret;
+       }
+
+       if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
+           !(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
+           test_sta_flag(sta, WLAN_STA_AUTH)) {
+               ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int sta_apply_parameters(struct ieee80211_local *local,
                                struct sta_info *sta,
                                struct station_parameters *params)
@@ -1096,52 +1159,20 @@ static int sta_apply_parameters(struct ieee80211_local *local,
        mask = params->sta_flags_mask;
        set = params->sta_flags_set;
 
-       /*
-        * In mesh mode, we can clear AUTHENTICATED flag but must
-        * also make ASSOCIATED follow appropriately for the driver
-        * API. See also below, after AUTHORIZED changes.
-        */
-       if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
-               /* cfg80211 should not allow this in non-mesh modes */
-               if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
-                       return -EINVAL;
-
-               if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
-                   !test_sta_flag(sta, WLAN_STA_AUTH)) {
-                       ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
-                       if (ret)
-                               return ret;
-                       ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
-               if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
-                       ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
-               else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-                       ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-               if (ret)
-                       return ret;
-       }
-
-       if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
-               /* cfg80211 should not allow this in non-mesh modes */
-               if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
-                       return -EINVAL;
-
-               if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
-                   test_sta_flag(sta, WLAN_STA_AUTH)) {
-                       ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
-                       if (ret)
-                               return ret;
-                       ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
-                       if (ret)
-                               return ret;
-               }
+       if (ieee80211_vif_is_mesh(&sdata->vif)) {
+               /*
+                * In mesh mode, ASSOCIATED isn't part of the nl80211
+                * API but must follow AUTHENTICATED for driver state.
+                */
+               if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+                       mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+               if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+                       set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
        }
 
+       ret = sta_apply_auth_flags(local, sta, mask, set);
+       if (ret)
+               return ret;
 
        if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
                if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
@@ -1187,10 +1218,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                sta->sta.aid = params->aid;
 
        /*
-        * FIXME: updating the following information is racy when this
-        *        function is called from ieee80211_change_station().
-        *        However, all this information should be static so
-        *        maybe we should just reject attemps to change it.
+        * Some of the following updates would be racy if called on an
+        * existing station, via ieee80211_change_station(). However,
+        * all such changes are rejected by cfg80211 except for updates
+        * changing the supported rates on an existing but not yet used
+        * TDLS peer.
         */
 
        if (params->listen_interval >= 0)
@@ -1221,18 +1253,33 @@ static int sta_apply_parameters(struct ieee80211_local *local,
 
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
-               if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
+               if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
+                       u32 changed = 0;
+
                        switch (params->plink_state) {
-                       case NL80211_PLINK_LISTEN:
                        case NL80211_PLINK_ESTAB:
+                               if (sta->plink_state != NL80211_PLINK_ESTAB)
+                                       changed = mesh_plink_inc_estab_count(
+                                                       sdata);
+                               sta->plink_state = params->plink_state;
+                               break;
+                       case NL80211_PLINK_LISTEN:
                        case NL80211_PLINK_BLOCKED:
+                       case NL80211_PLINK_OPN_SNT:
+                       case NL80211_PLINK_OPN_RCVD:
+                       case NL80211_PLINK_CNF_RCVD:
+                       case NL80211_PLINK_HOLDING:
+                               if (sta->plink_state == NL80211_PLINK_ESTAB)
+                                       changed = mesh_plink_dec_estab_count(
+                                                       sdata);
                                sta->plink_state = params->plink_state;
                                break;
                        default:
                                /*  nothing  */
                                break;
                        }
-               else
+                       ieee80211_bss_info_change_notify(sdata, changed);
+               } else {
                        switch (params->plink_action) {
                        case PLINK_ACTION_OPEN:
                                mesh_plink_open(sta);
@@ -1241,6 +1288,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                mesh_plink_block(sta);
                                break;
                        }
+               }
 #endif
        }
 
@@ -1275,6 +1323,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        if (!sta)
                return -ENOMEM;
 
+       /*
+        * defaults -- if userspace wants something else we'll
+        * change it accordingly in sta_apply_parameters()
+        */
        sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
        sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
 
@@ -1311,7 +1363,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1319,7 +1370,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        if (mac)
                return sta_info_destroy_addr_bss(sdata, mac);
 
-       sta_info_flush(local, sdata);
+       sta_info_flush(sdata);
        return 0;
 }
 
@@ -1625,6 +1676,9 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
        memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
                                                sizeof(setup->mcast_rate));
 
+       sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
+       sdata->vif.bss_conf.dtim_period = setup->dtim_period;
+
        return 0;
 }
 
@@ -2207,7 +2261,8 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+           sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
                return -EOPNOTSUPP;
 
        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
index 80e55527504b91cd71b6d33a946507ad10b59c7e..1bfe0a8b19d222c95c3878d157114e9e85a0443b 100644 (file)
@@ -381,7 +381,8 @@ void ieee80211_iter_chan_contexts_atomic(
 
        rcu_read_lock();
        list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
-               iter(hw, &ctx->conf, iter_data);
+               if (ctx->driver_present)
+                       iter(hw, &ctx->conf, iter_data);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);
index 698dc7e6f309847373541748c3cc4a2f40b67f58..0c07f94c53780cbf8b00609a24af435128923b17 100644 (file)
@@ -207,6 +207,14 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 {
        might_sleep();
 
+       WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON |
+                               BSS_CHANGED_BEACON_ENABLED) &&
+                    sdata->vif.type != NL80211_IFTYPE_AP &&
+                    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+                    sdata->vif.type != NL80211_IFTYPE_MESH_POINT);
+       WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE &&
+                    changed & ~BSS_CHANGED_IDLE);
+
        check_sdata_in_driver(sdata);
 
        trace_drv_bss_info_changed(local, sdata, info, changed);
@@ -913,6 +921,8 @@ static inline int drv_add_chanctx(struct ieee80211_local *local,
        if (local->ops->add_chanctx)
                ret = local->ops->add_chanctx(&local->hw, &ctx->conf);
        trace_drv_return_int(local, ret);
+       if (!ret)
+               ctx->driver_present = true;
 
        return ret;
 }
@@ -924,6 +934,7 @@ static inline void drv_remove_chanctx(struct ieee80211_local *local,
        if (local->ops->remove_chanctx)
                local->ops->remove_chanctx(&local->hw, &ctx->conf);
        trace_drv_return_void(local);
+       ctx->driver_present = false;
 }
 
 static inline void drv_change_chanctx(struct ieee80211_local *local,
@@ -931,8 +942,10 @@ static inline void drv_change_chanctx(struct ieee80211_local *local,
                                      u32 changed)
 {
        trace_drv_change_chanctx(local, ctx, changed);
-       if (local->ops->change_chanctx)
+       if (local->ops->change_chanctx) {
+               WARN_ON_ONCE(!ctx->driver_present);
                local->ops->change_chanctx(&local->hw, &ctx->conf, changed);
+       }
        trace_drv_return_void(local);
 }
 
@@ -945,10 +958,12 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
        check_sdata_in_driver(sdata);
 
        trace_drv_assign_vif_chanctx(local, sdata, ctx);
-       if (local->ops->assign_vif_chanctx)
+       if (local->ops->assign_vif_chanctx) {
+               WARN_ON_ONCE(!ctx->driver_present);
                ret = local->ops->assign_vif_chanctx(&local->hw,
                                                     &sdata->vif,
                                                     &ctx->conf);
+       }
        trace_drv_return_int(local, ret);
 
        return ret;
@@ -961,10 +976,12 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
        check_sdata_in_driver(sdata);
 
        trace_drv_unassign_vif_chanctx(local, sdata, ctx);
-       if (local->ops->unassign_vif_chanctx)
+       if (local->ops->unassign_vif_chanctx) {
+               WARN_ON_ONCE(!ctx->driver_present);
                local->ops->unassign_vif_chanctx(&local->hw,
                                                 &sdata->vif,
                                                 &ctx->conf);
+       }
        trace_drv_return_void(local);
 }
 
index a71d891794a40ab96134ec16eef5568e8b5b3eca..61ac7c48ac0c48dfff325c5d11bdcf5ef549f907 100644 (file)
@@ -62,6 +62,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
        __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40);
        __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40);
 
+       /* Allow user to disable SGI-20 (SGI-40 is handled above) */
+       __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_20);
+
        /* Allow user to disable the max-AMSDU bit. */
        __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU);
 
@@ -117,6 +120,21 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
                   IEEE80211_HT_CAP_SGI_20 |
                   IEEE80211_HT_CAP_SGI_40 |
                   IEEE80211_HT_CAP_DSSSCCK40));
+
+       /* Unset 40 MHz if we're not using a 40 MHz channel */
+       switch (sdata->vif.bss_conf.chandef.width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+       case NL80211_CHAN_WIDTH_20:
+               ht_cap->cap &= ~IEEE80211_HT_CAP_SGI_40;
+               ht_cap->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+               break;
+       case NL80211_CHAN_WIDTH_40:
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_80P80:
+       case NL80211_CHAN_WIDTH_160:
+               break;
+       }
+
        /*
         * The STBC bits are asymmetric -- if we don't have
         * TX then mask out the peer's RX and vice versa.
@@ -179,16 +197,19 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
        ieee80211_apply_htcap_overrides(sdata, ht_cap);
 }
 
-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
+                                        enum ieee80211_agg_stop_reason reason)
 {
        int i;
 
        cancel_work_sync(&sta->ampdu_mlme.work);
 
        for (i = 0; i <  IEEE80211_NUM_TIDS; i++) {
-               __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx);
+               __ieee80211_stop_tx_ba_session(sta, i, reason);
                __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
-                                              WLAN_REASON_QSTA_LEAVE_QBSS, tx);
+                                              WLAN_REASON_QSTA_LEAVE_QBSS,
+                                              reason != AGG_STOP_DESTROY_STA &&
+                                              reason != AGG_STOP_PEER_REQUEST);
        }
 }
 
@@ -245,8 +266,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
                if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
                                                 &tid_tx->state))
                        ___ieee80211_stop_tx_ba_session(sta, tid,
-                                                       WLAN_BACK_INITIATOR,
-                                                       true);
+                                                       AGG_STOP_LOCAL_REQUEST);
        }
        mutex_unlock(&sta->ampdu_mlme.mtx);
 }
@@ -314,8 +334,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
                                               true);
        else
-               __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
-                                              true);
+               __ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_PEER_REQUEST);
 }
 
 int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
index 6b7644e818d8f30629513318d4f9a17e4e622606..b4b866f41919a5c64b73837df29b301860702c25 100644 (file)
@@ -67,7 +67,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
 
        if (!ether_addr_equal(ifibss->bssid, bssid))
-               sta_info_flush(sdata->local, sdata);
+               sta_info_flush(sdata);
 
        /* if merging, indicate to driver that we leave the old IBSS */
        if (sdata->vif.bss_conf.ibss_joined) {
@@ -191,6 +191,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        rcu_assign_pointer(ifibss->presp, skb);
 
+       sdata->vif.bss_conf.enable_beacon = true;
        sdata->vif.bss_conf.beacon_int = beacon_int;
        sdata->vif.bss_conf.basic_rates = basic_rates;
        bss_change = BSS_CHANGED_BEACON_INT;
@@ -425,11 +426,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
 }
 
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
-                                 struct ieee80211_mgmt *mgmt,
-                                 size_t len,
+                                 struct ieee80211_mgmt *mgmt, size_t len,
                                  struct ieee80211_rx_status *rx_status,
-                                 struct ieee802_11_elems *elems,
-                                 bool beacon)
+                                 struct ieee802_11_elems *elems)
 {
        struct ieee80211_local *local = sdata->local;
        int freq;
@@ -530,7 +529,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        }
 
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
-                                       channel, beacon);
+                                       channel);
        if (!bss)
                return;
 
@@ -877,14 +876,21 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        ieee80211_tx_skb(sdata, skb);
 }
 
-static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_mgmt *mgmt,
-                                        size_t len,
-                                        struct ieee80211_rx_status *rx_status)
+static
+void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
+                                   struct ieee80211_mgmt *mgmt, size_t len,
+                                   struct ieee80211_rx_status *rx_status)
 {
        size_t baselen;
        struct ieee802_11_elems elems;
 
+       BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
+                    offsetof(typeof(mgmt->u.beacon), variable));
+
+       /*
+        * either beacon or probe_resp but the variable field is at the
+        * same offset
+        */
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
        if (baselen > len)
                return;
@@ -892,25 +898,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
                                &elems);
 
-       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
-}
-
-static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len,
-                                    struct ieee80211_rx_status *rx_status)
-{
-       size_t baselen;
-       struct ieee802_11_elems elems;
-
-       /* Process beacon from the current BSS */
-       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-       if (baselen > len)
-               return;
-
-       ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-
-       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
+       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
 }
 
 void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -934,12 +922,9 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                ieee80211_rx_mgmt_probe_req(sdata, skb);
                break;
        case IEEE80211_STYPE_PROBE_RESP:
-               ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
-                                            rx_status);
-               break;
        case IEEE80211_STYPE_BEACON:
-               ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
-                                        rx_status);
+               ieee80211_rx_mgmt_probe_beacon(sdata, mgmt, skb->len,
+                                              rx_status);
                break;
        case IEEE80211_STYPE_AUTH:
                ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len);
@@ -1182,7 +1167,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        memset(ifibss->bssid, 0, ETH_ALEN);
        ifibss->ssid_len = 0;
 
-       sta_info_flush(sdata->local, sdata);
+       sta_info_flush(sdata);
 
        spin_lock_bh(&ifibss->incomplete_lock);
        while (!list_empty(&ifibss->incomplete_stations)) {
@@ -1205,6 +1190,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
        sdata->vif.bss_conf.ibss_joined = false;
        sdata->vif.bss_conf.ibss_creator = false;
+       sdata->vif.bss_conf.enable_beacon = false;
+       clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
                                                BSS_CHANGED_IBSS);
        synchronize_rcu();
index 2ed065c095629403c42574872fec6a8b85819871..63f0430c131efa37b3c79c49171ebaeaf141422a 100644 (file)
@@ -405,6 +405,8 @@ struct ieee80211_mgd_assoc_data {
 
        u8 ap_ht_param;
 
+       struct ieee80211_vht_cap ap_vht_cap;
+
        size_t ie_len;
        u8 ie[];
 };
@@ -659,10 +661,13 @@ enum ieee80211_sub_if_data_flags {
  *     change handling while the interface is up
  * @SDATA_STATE_OFFCHANNEL: This interface is currently in offchannel
  *     mode, so queues are stopped
+ * @SDATA_STATE_OFFCHANNEL_BEACON_STOPPED: Beaconing was stopped due
+ *     to offchannel, reset when offchannel returns
  */
 enum ieee80211_sdata_state_bits {
        SDATA_STATE_RUNNING,
        SDATA_STATE_OFFCHANNEL,
+       SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
 };
 
 /**
@@ -685,6 +690,7 @@ struct ieee80211_chanctx {
 
        enum ieee80211_chanctx_mode mode;
        int refcount;
+       bool driver_present;
 
        struct ieee80211_chanctx_conf conf;
 };
@@ -783,6 +789,11 @@ struct ieee80211_sub_if_data {
                struct dentry *default_mgmt_key;
        } debugfs;
 #endif
+
+#ifdef CONFIG_PM
+       struct ieee80211_bss_conf suspend_bss_conf;
+#endif
+
        /* must be last, dynamically sized area in this! */
        struct ieee80211_vif vif;
 };
@@ -1346,8 +1357,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                          struct ieee80211_mgmt *mgmt,
                          size_t len,
                          struct ieee802_11_elems *elems,
-                         struct ieee80211_channel *channel,
-                         bool beacon);
+                         struct ieee80211_channel *channel);
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
                          struct ieee80211_bss *bss);
 
@@ -1420,7 +1430,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                     u16 initiator, u16 reason, bool stop);
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                    u16 initiator, u16 reason, bool stop);
-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx);
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
+                                        enum ieee80211_agg_stop_reason reason);
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                             struct sta_info *sta,
                             struct ieee80211_mgmt *mgmt, size_t len);
@@ -1434,11 +1445,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                                     size_t len);
 
 int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                  enum ieee80211_back_parties initiator,
-                                  bool tx);
+                                  enum ieee80211_agg_stop_reason reason);
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                   enum ieee80211_back_parties initiator,
-                                   bool tx);
+                                   enum ieee80211_agg_stop_reason reason);
 void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
 void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
 void ieee80211_ba_session_work(struct work_struct *work);
index 8be854e86cd987d61e01cc7eabc8f7ddb068eff3..06fac2991d4003a72715f10dc49ae4f032cf95d7 100644 (file)
@@ -747,7 +747,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        unsigned long flags;
        struct sk_buff *skb, *tmp;
        u32 hw_reconf_flags = 0;
-       int i;
+       int i, flushed;
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
@@ -772,11 +772,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
         * (because if we remove a STA after ops->remove_interface()
         * the driver will have removed the vif info already!)
         *
-        * This is relevant only in AP, WDS and mesh modes, since in
-        * all other modes we've already removed all stations when
-        * disconnecting etc.
+        * This is relevant only in WDS mode, in all other modes we've
+        * already removed all stations when disconnecting or similar,
+        * so warn otherwise.
+        *
+        * We call sta_info_flush_cleanup() later, to combine RCU waits.
         */
-       sta_info_flush(local, sdata);
+       flushed = sta_info_flush_defer(sdata);
+       WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
+                    (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));
 
        /*
         * Don't count this interface for promisc/allmulti while it
@@ -859,11 +863,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                cancel_work_sync(&sdata->work);
                /*
                 * When we get here, the interface is marked down.
-                * Call synchronize_rcu() to wait for the RX path
-                * should it be using the interface and enqueuing
-                * frames at this very time on another CPU.
+                *
+                * sta_info_flush_cleanup() requires rcu_barrier()
+                * first to wait for the station call_rcu() calls
+                * to complete, here we need at least sychronize_rcu()
+                * it to wait for the RX path in case it is using the
+                * interface and enqueuing frames at this very time on
+                * another CPU.
                 */
-               synchronize_rcu();
+               rcu_barrier();
+               sta_info_flush_cleanup(sdata);
+
                skb_queue_purge(&sdata->skb_queue);
 
                /*
@@ -961,7 +971,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
  */
 static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_local *local = sdata->local;
        int flushed;
        int i;
 
@@ -977,7 +986,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
        if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_rmc_free(sdata);
 
-       flushed = sta_info_flush(local, sdata);
+       flushed = sta_info_flush(sdata);
        WARN_ON(flushed);
 }
 
@@ -1218,6 +1227,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP:
                skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
                INIT_LIST_HEAD(&sdata->u.ap.vlans);
+               sdata->vif.bss_conf.bssid = sdata->vif.addr;
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
                type = NL80211_IFTYPE_STATION;
@@ -1225,9 +1235,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                sdata->vif.p2p = true;
                /* fall through */
        case NL80211_IFTYPE_STATION:
+               sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
                ieee80211_sta_setup_sdata(sdata);
                break;
        case NL80211_IFTYPE_ADHOC:
+               sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
                ieee80211_ibss_setup_sdata(sdata);
                break;
        case NL80211_IFTYPE_MESH_POINT:
@@ -1241,8 +1253,12 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                                      MONITOR_FLAG_OTHER_BSS;
                break;
        case NL80211_IFTYPE_WDS:
+               sdata->vif.bss_conf.bssid = NULL;
+               break;
        case NL80211_IFTYPE_AP_VLAN:
+               break;
        case NL80211_IFTYPE_P2P_DEVICE:
+               sdata->vif.bss_conf.bssid = sdata->vif.addr;
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
        case NUM_NL80211_IFTYPES:
index 1b087fff93e70f278c638c017789f0ba7fb4f1b7..39cfe8f10ad2dc50d929709715b2763c8e2cccd7 100644 (file)
@@ -207,76 +207,10 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                                      u32 changed)
 {
        struct ieee80211_local *local = sdata->local;
-       static const u8 zero[ETH_ALEN] = { 0 };
 
        if (!changed)
                return;
 
-       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
-       } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-               sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
-       else if (sdata->vif.type == NL80211_IFTYPE_AP)
-               sdata->vif.bss_conf.bssid = sdata->vif.addr;
-       else if (sdata->vif.type == NL80211_IFTYPE_WDS)
-               sdata->vif.bss_conf.bssid = NULL;
-       else if (ieee80211_vif_is_mesh(&sdata->vif)) {
-               sdata->vif.bss_conf.bssid = zero;
-       } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
-               sdata->vif.bss_conf.bssid = sdata->vif.addr;
-               WARN_ONCE(changed & ~(BSS_CHANGED_IDLE),
-                         "P2P Device BSS changed %#x", changed);
-       } else {
-               WARN_ON(1);
-               return;
-       }
-
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_WDS:
-       case NL80211_IFTYPE_MESH_POINT:
-               break;
-       default:
-               /* do not warn to simplify caller in scan.c */
-               changed &= ~BSS_CHANGED_BEACON_ENABLED;
-               if (WARN_ON(changed & BSS_CHANGED_BEACON))
-                       return;
-               break;
-       }
-
-       if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               if (local->quiescing || !ieee80211_sdata_running(sdata) ||
-                   test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) {
-                       sdata->vif.bss_conf.enable_beacon = false;
-               } else {
-                       /*
-                        * Beacon should be enabled, but AP mode must
-                        * check whether there is a beacon configured.
-                        */
-                       switch (sdata->vif.type) {
-                       case NL80211_IFTYPE_AP:
-                               sdata->vif.bss_conf.enable_beacon =
-                                       !!sdata->u.ap.beacon;
-                               break;
-                       case NL80211_IFTYPE_ADHOC:
-                               sdata->vif.bss_conf.enable_beacon =
-                                       !!sdata->u.ibss.presp;
-                               break;
-#ifdef CONFIG_MAC80211_MESH
-                       case NL80211_IFTYPE_MESH_POINT:
-                               sdata->vif.bss_conf.enable_beacon =
-                                       !!sdata->u.mesh.mesh_id_len;
-                               break;
-#endif
-                       default:
-                               /* not reached */
-                               WARN_ON(1);
-                               break;
-                       }
-               }
-       }
-
        drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed);
 }
 
@@ -537,6 +471,7 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
 
        .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
                                IEEE80211_HT_CAP_MAX_AMSDU |
+                               IEEE80211_HT_CAP_SGI_20 |
                                IEEE80211_HT_CAP_SGI_40),
        .mcs = {
                .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -606,7 +541,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
                           NL80211_FEATURE_SAE |
                           NL80211_FEATURE_HT_IBSS |
-                          NL80211_FEATURE_VIF_TXPOWER;
+                          NL80211_FEATURE_VIF_TXPOWER |
+                          NL80211_FEATURE_FULL_AP_CLIENT_STATE;
 
        if (!ops->hw_scan)
                wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
index 649ad513547f99728d43dbeeabcd2b58d7862c30..694e27376afa151941ef5628c3fa83ae32867b15 100644 (file)
 int mesh_allocated;
 static struct kmem_cache *rm_cache;
 
-#ifdef CONFIG_MAC80211_MESH
 bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
 {
        return (mgmt->u.action.u.mesh_action.action_code ==
                        WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
 }
-#else
-bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
-{ return false; }
-#endif
 
 void ieee80211s_init(void)
 {
@@ -607,6 +602,12 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct ieee80211_local *local = sdata->local;
+       u32 changed = BSS_CHANGED_BEACON |
+                     BSS_CHANGED_BEACON_ENABLED |
+                     BSS_CHANGED_HT |
+                     BSS_CHANGED_BASIC_RATES |
+                     BSS_CHANGED_BEACON_INT;
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
 
        local->fif_other_bss++;
        /* mesh ifaces must set allmulti to forward mcast traffic */
@@ -624,15 +625,16 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
        ieee80211_queue_work(&local->hw, &sdata->work);
        sdata->vif.bss_conf.ht_operation_mode =
                                ifmsh->mshcfg.ht_opmode;
-       sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
+       sdata->vif.bss_conf.enable_beacon = true;
        sdata->vif.bss_conf.basic_rates =
-               ieee80211_mandatory_rates(sdata->local,
-                                         ieee80211_get_sdata_band(sdata));
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
-                                               BSS_CHANGED_BEACON_ENABLED |
-                                               BSS_CHANGED_HT |
-                                               BSS_CHANGED_BASIC_RATES |
-                                               BSS_CHANGED_BEACON_INT);
+               ieee80211_mandatory_rates(local, band);
+
+       if (band == IEEE80211_BAND_5GHZ) {
+               sdata->vif.bss_conf.use_short_slot = true;
+               changed |= BSS_CHANGED_ERP_SLOT;
+       }
+
+       ieee80211_bss_info_change_notify(sdata, changed);
 
        netif_carrier_on(sdata->dev);
 }
@@ -646,10 +648,12 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 
        /* stop the beacon */
        ifmsh->mesh_id_len = 0;
+       sdata->vif.bss_conf.enable_beacon = false;
+       clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
        /* flush STAs and mpaths on this iface */
-       sta_info_flush(sdata->local, sdata);
+       sta_info_flush(sdata);
        mesh_path_flush_by_iface(sdata);
 
        del_timer_sync(&sdata->u.mesh.housekeeping_timer);
@@ -805,6 +809,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       static u8 zero_addr[ETH_ALEN] = {};
 
        setup_timer(&ifmsh->housekeeping_timer,
                    ieee80211_mesh_housekeeping_timer,
@@ -830,4 +835,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
        INIT_LIST_HEAD(&ifmsh->preq_queue.list);
        spin_lock_init(&ifmsh->mesh_preq_queue_lock);
        spin_lock_init(&ifmsh->sync_offset_lock);
+
+       sdata->vif.bss_conf.bssid = zero_addr;
 }
index 84c28c6101cdd2ef832920677d05b7f02b27ada2..aff301544c7fb30cc0fb3b8e4309a2cfead6909d 100644 (file)
@@ -191,8 +191,6 @@ struct mesh_rmc {
 #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
 #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
 
-#define MESH_DEFAULT_BEACON_INTERVAL           1000    /* in 1024 us units */
-
 #define MESH_PATH_EXPIRE (600 * HZ)
 
 /* Default maximum number of plinks per interface */
@@ -307,6 +305,20 @@ extern int mesh_paths_generation;
 #ifdef CONFIG_MAC80211_MESH
 extern int mesh_allocated;
 
+static inline
+u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+       atomic_inc(&sdata->u.mesh.estab_plinks);
+       return mesh_accept_plinks_update(sdata);
+}
+
+static inline
+u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+       atomic_dec(&sdata->u.mesh.estab_plinks);
+       return mesh_accept_plinks_update(sdata);
+}
+
 static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
 {
        return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks -
index 2659e428b80c86cf367a75b034c8d89a856f28a1..6b4603a9003189c6de53c37d46c8441f9803eaa9 100644 (file)
@@ -220,12 +220,14 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
 }
 
 /**
- * mesh_send_path error - Sends a PERR mesh management frame
+ * mesh_path_error_tx - Sends a PERR mesh management frame
  *
+ * @ttl: allowed remaining hops
  * @target: broken destination
  * @target_sn: SN of the broken destination
  * @target_rcode: reason code for this PERR
  * @ra: node this frame is addressed to
+ * @sdata: local mesh subif
  *
  * Note: This function may be called with driver locks taken that the driver
  * also acquires in the TX path.  To avoid a deadlock we don't transmit the
@@ -353,6 +355,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
  * @sdata: local mesh subif
  * @mgmt: mesh management frame
  * @hwmp_ie: hwmp information element (PREP or PREQ)
+ * @action: type of hwmp ie
  *
  * This function updates the path routing information to the originator and the
  * transmitter of a HWMP PREQ or PREP frame.
index 4b274e9c91a5f19c526c9c91d290c9fc574d4098..9e0416696a834d1481a6f47385b97bbc8b4369db 100644 (file)
@@ -41,20 +41,6 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                enum ieee80211_self_protected_actioncode action,
                u8 *da, __le16 llid, __le16 plid, __le16 reason);
 
-static inline
-u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
-{
-       atomic_inc(&sdata->u.mesh.estab_plinks);
-       return mesh_accept_plinks_update(sdata);
-}
-
-static inline
-u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
-{
-       atomic_dec(&sdata->u.mesh.estab_plinks);
-       return mesh_accept_plinks_update(sdata);
-}
-
 /**
  * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
  *
index a3552929a21d68f469696c4131ffb6296becd5df..e930175771ffa088dd7d58bf115c8f2cd5908b3c 100644 (file)
@@ -199,11 +199,11 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
        case NL80211_CHAN_WIDTH_40:
                if (sdata->vif.bss_conf.chandef.chan->center_freq >
                                sdata->vif.bss_conf.chandef.center_freq1 &&
-                   chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+                   chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
                        disable_40 = true;
                if (sdata->vif.bss_conf.chandef.chan->center_freq <
                                sdata->vif.bss_conf.chandef.center_freq1 &&
-                   chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+                   chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
                        disable_40 = true;
                break;
        default:
@@ -341,11 +341,13 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
 
 static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
                                 struct sk_buff *skb,
-                                struct ieee80211_supported_band *sband)
+                                struct ieee80211_supported_band *sband,
+                                struct ieee80211_vht_cap *ap_vht_cap)
 {
        u8 *pos;
        u32 cap;
        struct ieee80211_sta_vht_cap vht_cap;
+       int i;
 
        BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
 
@@ -364,6 +366,42 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
                cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
        }
 
+       /*
+        * Some APs apparently get confused if our capabilities are better
+        * than theirs, so restrict what we advertise in the assoc request.
+        */
+       if (!(ap_vht_cap->vht_cap_info &
+                       cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)))
+               cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+
+       if (!(ap_vht_cap->vht_cap_info &
+                       cpu_to_le32(IEEE80211_VHT_CAP_TXSTBC)))
+               cap &= ~(IEEE80211_VHT_CAP_RXSTBC_1 |
+                        IEEE80211_VHT_CAP_RXSTBC_3 |
+                        IEEE80211_VHT_CAP_RXSTBC_4);
+
+       for (i = 0; i < 8; i++) {
+               int shift = i * 2;
+               u16 mask = IEEE80211_VHT_MCS_NOT_SUPPORTED << shift;
+               u16 ap_mcs, our_mcs;
+
+               ap_mcs = (le16_to_cpu(ap_vht_cap->supp_mcs.tx_mcs_map) &
+                                                               mask) >> shift;
+               our_mcs = (le16_to_cpu(vht_cap.vht_mcs.rx_mcs_map) &
+                                                               mask) >> shift;
+
+               switch (ap_mcs) {
+               default:
+                       if (our_mcs <= ap_mcs)
+                               break;
+                       /* fall through */
+               case IEEE80211_VHT_MCS_NOT_SUPPORTED:
+                       vht_cap.vht_mcs.rx_mcs_map &= cpu_to_le16(~mask);
+                       vht_cap.vht_mcs.rx_mcs_map |=
+                               cpu_to_le16(ap_mcs << shift);
+               }
+       }
+
        /* reserve and fill IE */
        pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
        ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
@@ -562,7 +600,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                                    sband, chan, sdata->smps_mode);
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
-               ieee80211_add_vht_ie(sdata, skb, sband);
+               ieee80211_add_vht_ie(sdata, skb, sband,
+                                    &assoc_data->ap_vht_cap);
 
        /* if present, add any custom non-vendor IEs that go after HT */
        if (assoc_data->ie_len && assoc_data->ie) {
@@ -1486,7 +1525,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        sta = sta_info_get(sdata, ifmgd->bssid);
        if (sta) {
                set_sta_flag(sta, WLAN_STA_BLOCK_BA);
-               ieee80211_sta_tear_down_BA_sessions(sta, false);
+               ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
        }
        mutex_unlock(&local->sta_mtx);
 
@@ -1521,7 +1560,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        memset(ifmgd->bssid, 0, ETH_ALEN);
 
        /* remove AP and TDLS peers */
-       sta_info_flush(local, sdata);
+       sta_info_flush_defer(sdata);
 
        /* finally reset all BSS / config parameters */
        changed |= ieee80211_reset_erp_info(sdata);
@@ -2369,8 +2408,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                  struct ieee80211_mgmt *mgmt, size_t len,
                                  struct ieee80211_rx_status *rx_status,
-                                 struct ieee802_11_elems *elems,
-                                 bool beacon)
+                                 struct ieee802_11_elems *elems)
 {
        struct ieee80211_local *local = sdata->local;
        int freq;
@@ -2404,7 +2442,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                return;
 
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
-                                       channel, beacon);
+                                       channel);
        if (bss)
                ieee80211_rx_bss_put(local, bss);
 
@@ -2447,7 +2485,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
                                &elems);
 
-       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
+       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
 
        if (ifmgd->associated &&
            ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
@@ -2528,8 +2566,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                ieee802_11_parse_elems(mgmt->u.beacon.variable,
                                       len - baselen, &elems);
 
-               ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
-                                     false);
+               ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
                ifmgd->assoc_data->have_beacon = true;
                ifmgd->assoc_data->sent_assoc = false;
                /* continue assoc process */
@@ -2682,8 +2719,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        ifmgd->beacon_crc = ncrc;
        ifmgd->beacon_crc_valid = true;
 
-       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
-                             true);
+       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
 
        if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
                                     elems.wmm_param_len))
@@ -3756,7 +3792,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_bss *bss = (void *)req->bss->priv;
        struct ieee80211_mgd_assoc_data *assoc_data;
        struct ieee80211_supported_band *sband;
-       const u8 *ssidie, *ht_ie;
+       const u8 *ssidie, *ht_ie, *vht_ie;
        int i, err;
 
        assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL);
@@ -3875,6 +3911,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                        ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
        else
                ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
+       vht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_VHT_CAPABILITY);
+       if (vht_ie && vht_ie[1] >= sizeof(struct ieee80211_vht_cap))
+               memcpy(&assoc_data->ap_vht_cap, vht_ie + 2,
+                      sizeof(struct ieee80211_vht_cap));
+       else
+               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
        rcu_read_unlock();
 
        if (bss->wmm_used && bss->uapsd_supported &&
index a3ad4c3c80a34229801bdbdd1124201485a2f671..82baf5b6ecf4cbac5accf2e38d33187df1545514 100644 (file)
@@ -125,11 +125,13 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
                        set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
 
                /* Check to see if we should disable beaconing. */
-               if (sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+               if (sdata->vif.bss_conf.enable_beacon) {
+                       set_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
+                               &sdata->state);
+                       sdata->vif.bss_conf.enable_beacon = false;
                        ieee80211_bss_info_change_notify(
                                sdata, BSS_CHANGED_BEACON_ENABLED);
+               }
 
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
                        netif_tx_stop_all_queues(sdata->dev);
@@ -178,11 +180,12 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
                        netif_tx_wake_all_queues(sdata->dev);
                }
 
-               if (sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+               if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
+                                      &sdata->state)) {
+                       sdata->vif.bss_conf.enable_beacon = true;
                        ieee80211_bss_info_change_notify(
                                sdata, BSS_CHANGED_BEACON_ENABLED);
+               }
        }
        mutex_unlock(&local->iflist_mtx);
 }
index 79a48f37d4092b27a88b8fa136f15a51812365f2..e45b83610e850fdf8df47f9f2774686665a13f8d 100644 (file)
@@ -7,25 +7,23 @@
 #include "led.h"
 
 /* return value indicates whether the driver should be further notified */
-static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
 {
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_STATION:
                ieee80211_sta_quiesce(sdata);
-               return true;
+               break;
        case NL80211_IFTYPE_ADHOC:
                ieee80211_ibss_quiesce(sdata);
-               return true;
+               break;
        case NL80211_IFTYPE_MESH_POINT:
                ieee80211_mesh_quiesce(sdata);
-               return true;
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_MONITOR:
-               /* don't tell driver about this */
-               return false;
+               break;
        default:
-               return true;
+               break;
        }
+
+       cancel_work_sync(&sdata->work);
 }
 
 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
@@ -44,7 +42,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                mutex_lock(&local->sta_mtx);
                list_for_each_entry(sta, &local->sta_list, list) {
                        set_sta_flag(sta, WLAN_STA_BLOCK_BA);
-                       ieee80211_sta_tear_down_BA_sessions(sta, true);
+                       ieee80211_sta_tear_down_BA_sessions(
+                                       sta, AGG_STOP_LOCAL_REQUEST);
                }
                mutex_unlock(&local->sta_mtx);
        }
@@ -94,10 +93,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                        WARN_ON(err != 1);
                        local->wowlan = false;
                } else {
-                       list_for_each_entry(sdata, &local->interfaces, list) {
-                               cancel_work_sync(&sdata->work);
-                               ieee80211_quiesce(sdata);
-                       }
+                       list_for_each_entry(sdata, &local->interfaces, list)
+                               if (ieee80211_sdata_running(sdata))
+                                       ieee80211_quiesce(sdata);
                        goto suspend;
                }
        }
@@ -124,17 +122,43 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
        /* remove all interfaces */
        list_for_each_entry(sdata, &local->interfaces, list) {
-               cancel_work_sync(&sdata->work);
+               static u8 zero_addr[ETH_ALEN] = {};
+               u32 changed = 0;
 
-               if (!ieee80211_quiesce(sdata))
+               if (!ieee80211_sdata_running(sdata))
                        continue;
 
-               if (!ieee80211_sdata_running(sdata))
+               switch (sdata->vif.type) {
+               case NL80211_IFTYPE_AP_VLAN:
+               case NL80211_IFTYPE_MONITOR:
+                       /* skip these */
                        continue;
+               case NL80211_IFTYPE_STATION:
+                       if (sdata->vif.bss_conf.assoc)
+                               changed = BSS_CHANGED_ASSOC |
+                                         BSS_CHANGED_BSSID |
+                                         BSS_CHANGED_IDLE;
+                       break;
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_MESH_POINT:
+                       if (sdata->vif.bss_conf.enable_beacon)
+                               changed = BSS_CHANGED_BEACON_ENABLED;
+                       break;
+               default:
+                       break;
+               }
+
+               ieee80211_quiesce(sdata);
+
+               sdata->suspend_bss_conf = sdata->vif.bss_conf;
+               memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf));
+               sdata->vif.bss_conf.idle = true;
+               if (sdata->suspend_bss_conf.bssid)
+                       sdata->vif.bss_conf.bssid = zero_addr;
 
-               /* disable beaconing */
-               ieee80211_bss_info_change_notify(sdata,
-                       BSS_CHANGED_BEACON_ENABLED);
+               /* disable beaconing or remove association */
+               ieee80211_bss_info_change_notify(sdata, changed);
 
                if (sdata->vif.type == NL80211_IFTYPE_AP &&
                    rcu_access_pointer(sdata->u.ap.beacon))
index 580704eba8b8495e0bdbf2268dfdc197b9983797..a19089565c4b84ed35a7b2c685d16c487a3ef356 100644 (file)
@@ -2353,7 +2353,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                    sdata->vif.type != NL80211_IFTYPE_ADHOC)
                        break;
 
-               /* verify action & smps_control are present */
+               /* verify action & smps_control/chanwidth are present */
                if (len < IEEE80211_MIN_ACTION_SIZE + 2)
                        goto invalid;
 
@@ -2392,6 +2392,35 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                                                 IEEE80211_RC_SMPS_CHANGED);
                        goto handled;
                }
+               case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
+                       struct ieee80211_supported_band *sband;
+                       u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
+                       bool old_40mhz, new_40mhz;
+
+                       /* If it doesn't support 40 MHz it can't change ... */
+                       if (!rx->sta->supports_40mhz)
+                               goto handled;
+
+                       old_40mhz = rx->sta->sta.ht_cap.cap &
+                                       IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       new_40mhz = chanwidth == IEEE80211_HT_CHANWIDTH_ANY;
+
+                       if (old_40mhz == new_40mhz)
+                               goto handled;
+
+                       if (new_40mhz)
+                               rx->sta->sta.ht_cap.cap |=
+                                       IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       else
+                               rx->sta->sta.ht_cap.cap &=
+                                       ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+                       sband = rx->local->hw.wiphy->bands[status->band];
+
+                       rate_control_rate_update(local, sband, rx->sta,
+                                                IEEE80211_RC_BW_CHANGED);
+                       goto handled;
+               }
                default:
                        goto invalid;
                }
index bf82e69d0601bf9210e817837b2af7725a9f7d87..607684c47d558a4a3d67d50cd72c617d8033396a 100644 (file)
@@ -65,12 +65,11 @@ static bool is_uapsd_supported(struct ieee802_11_elems *elems)
 struct ieee80211_bss *
 ieee80211_bss_info_update(struct ieee80211_local *local,
                          struct ieee80211_rx_status *rx_status,
-                         struct ieee80211_mgmt *mgmt,
-                         size_t len,
+                         struct ieee80211_mgmt *mgmt, size_t len,
                          struct ieee802_11_elems *elems,
-                         struct ieee80211_channel *channel,
-                         bool beacon)
+                         struct ieee80211_channel *channel)
 {
+       bool beacon = ieee80211_is_beacon(mgmt->frame_control);
        struct cfg80211_bss *cbss;
        struct ieee80211_bss *bss;
        int clen, srlen;
@@ -203,7 +202,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
 
        bss = ieee80211_bss_info_update(local, rx_status,
                                        mgmt, skb->len, &elems,
-                                       channel, beacon);
+                                       channel);
        if (bss)
                ieee80211_rx_bss_put(local, bss);
 }
index ca9fde1981889a559efa6b49385f071f1475a06f..9d864ed5f3da15c05c12d5d1a5f0bf14c645e781 100644 (file)
@@ -104,6 +104,16 @@ static void cleanup_single_sta(struct sta_info *sta)
         * neither mac80211 nor the driver can reference this
         * sta struct any more except by still existing timers
         * associated with this station that we clean up below.
+        *
+        * Note though that this still uses the sdata and even
+        * calls the driver in AP and mesh mode, so interfaces
+        * of those types mush use call sta_info_flush_cleanup()
+        * (typically via sta_info_flush()) before deconfiguring
+        * the driver.
+        *
+        * In station mode, nothing happens here so it doesn't
+        * have to (and doesn't) do that, this is intentional to
+        * speed up roaming.
         */
 
        if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
@@ -774,7 +784,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
         * will be sufficient.
         */
        set_sta_flag(sta, WLAN_STA_BLOCK_BA);
-       ieee80211_sta_tear_down_BA_sessions(sta, false);
+       ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
 
        ret = sta_info_hash_del(local, sta);
        if (ret)
@@ -885,20 +895,12 @@ void sta_info_init(struct ieee80211_local *local)
 void sta_info_stop(struct ieee80211_local *local)
 {
        del_timer_sync(&local->sta_cleanup);
-       sta_info_flush(local, NULL);
 }
 
-/**
- * sta_info_flush - flush matching STA entries from the STA table
- *
- * Returns the number of removed STA entries.
- *
- * @local: local interface data
- * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs
- */
-int sta_info_flush(struct ieee80211_local *local,
-                  struct ieee80211_sub_if_data *sdata)
+
+int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta, *tmp;
        int ret = 0;
 
@@ -906,30 +908,22 @@ int sta_info_flush(struct ieee80211_local *local,
 
        mutex_lock(&local->sta_mtx);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
-               if (!sdata || sdata == sta->sdata) {
+               if (sdata == sta->sdata) {
                        WARN_ON(__sta_info_destroy(sta));
                        ret++;
                }
        }
        mutex_unlock(&local->sta_mtx);
 
-       rcu_barrier();
-
-       if (sdata) {
-               ieee80211_cleanup_sdata_stas(sdata);
-               cancel_work_sync(&sdata->cleanup_stations_wk);
-       } else {
-               mutex_lock(&local->iflist_mtx);
-               list_for_each_entry(sdata, &local->interfaces, list) {
-                       ieee80211_cleanup_sdata_stas(sdata);
-                       cancel_work_sync(&sdata->cleanup_stations_wk);
-               }
-               mutex_unlock(&local->iflist_mtx);
-       }
-
        return ret;
 }
 
+void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata)
+{
+       ieee80211_cleanup_sdata_stas(sdata);
+       cancel_work_sync(&sdata->cleanup_stations_wk);
+}
+
 void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                          unsigned long exp_time)
 {
index 37c1889afd3ae02f9d9d5f2573738a28d26c266e..af7d78aa55230e49e07252d9e87ef7c2f4fb2b31 100644 (file)
@@ -92,6 +92,13 @@ enum ieee80211_sta_info_flags {
 #define HT_AGG_STATE_WANT_START                4
 #define HT_AGG_STATE_WANT_STOP         5
 
+enum ieee80211_agg_stop_reason {
+       AGG_STOP_DECLINED,
+       AGG_STOP_LOCAL_REQUEST,
+       AGG_STOP_PEER_REQUEST,
+       AGG_STOP_DESTROY_STA,
+};
+
 /**
  * struct tid_ampdu_tx - TID aggregation information (Tx).
  *
@@ -548,8 +555,39 @@ void sta_info_recalc_tim(struct sta_info *sta);
 
 void sta_info_init(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
-int sta_info_flush(struct ieee80211_local *local,
-                  struct ieee80211_sub_if_data *sdata);
+int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata);
+
+/**
+ * sta_info_flush_cleanup - flush the sta_info cleanup queue
+ * @sdata: the interface
+ *
+ * Flushes the sta_info cleanup queue for a given interface;
+ * this is necessary before the interface is removed or, for
+ * AP/mesh interfaces, before it is deconfigured.
+ *
+ * Note an rcu_barrier() must precede the function, after all
+ * stations have been flushed/removed to ensure the call_rcu()
+ * calls that add stations to the cleanup queue have completed.
+ */
+void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata);
+
+/**
+ * sta_info_flush - flush matching STA entries from the STA table
+ *
+ * Returns the number of removed STA entries.
+ *
+ * @sdata: sdata to remove all stations from
+ */
+static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata)
+{
+       int ret = sta_info_flush_defer(sdata);
+
+       rcu_barrier();
+       sta_info_flush_cleanup(sdata);
+
+       return ret;
+}
+
 void sta_set_rate_info_tx(struct sta_info *sta,
                          const struct ieee80211_tx_rate *rate,
                          struct rate_info *rinfo);
index a8270b441a6f93249e095c74be849bdf9ce39f9b..41861b91daa3884bce04880beb4ad707ed301e4c 100644 (file)
 #define VIF_PR_FMT     " vif:%s(%d%s)"
 #define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
 
-#define CHANCTX_ENTRY  __field(u32, control_freq)                              \
+#define CHANDEF_ENTRY  __field(u32, control_freq)                              \
                        __field(u32, chan_width)                                \
                        __field(u32, center_freq1)                              \
-                       __field(u32, center_freq2)                              \
+                       __field(u32, center_freq2)
+#define CHANDEF_ASSIGN(c)                                                      \
+                       __entry->control_freq = (c)->chan->center_freq;         \
+                       __entry->chan_width = (c)->width;                       \
+                       __entry->center_freq1 = (c)->center_freq1;              \
+                       __entry->center_freq1 = (c)->center_freq2;
+#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
+#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width,             \
+                       __entry->center_freq1, __entry->center_freq2
+
+#define CHANCTX_ENTRY  CHANDEF_ENTRY                                           \
                        __field(u8, rx_chains_static)                           \
                        __field(u8, rx_chains_dynamic)
-#define CHANCTX_ASSIGN __entry->control_freq = ctx->conf.def.chan->center_freq;\
-                       __entry->chan_width = ctx->conf.def.width;              \
-                       __entry->center_freq1 = ctx->conf.def.center_freq1;     \
-                       __entry->center_freq2 = ctx->conf.def.center_freq2;     \
+#define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def)                          \
                        __entry->rx_chains_static = ctx->conf.rx_chains_static; \
                        __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
-#define CHANCTX_PR_FMT " control:%d MHz width:%d center: %d/%d MHz chains:%d/%d"
-#define CHANCTX_PR_ARG __entry->control_freq, __entry->chan_width,             \
-                       __entry->center_freq1, __entry->center_freq2,           \
+#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d"
+#define CHANCTX_PR_ARG CHANDEF_PR_ARG,                                         \
                        __entry->rx_chains_static, __entry->rx_chains_dynamic
 
 
index 467c1d1b66f2f5615182abd689349027b88abe64..f32d68186dbc73948b664fa66fe49723e418849a 100644 (file)
@@ -2264,9 +2264,8 @@ void ieee80211_tx_pending(unsigned long data)
 
 /* functions for drivers to get certain frames */
 
-static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
-                                    struct ps_data *ps,
-                                    struct sk_buff *skb)
+static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+                                      struct ps_data *ps, struct sk_buff *skb)
 {
        u8 *pos, *tim;
        int aid0 = 0;
@@ -2328,6 +2327,31 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
        }
 }
 
+static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+                                   struct ps_data *ps, struct sk_buff *skb)
+{
+       struct ieee80211_local *local = sdata->local;
+
+       /*
+        * Not very nice, but we want to allow the driver to call
+        * ieee80211_beacon_get() as a response to the set_tim()
+        * callback. That, however, is already invoked under the
+        * sta_lock to guarantee consistent and race-free update
+        * of the tim bitmap in mac80211 and the driver.
+        */
+       if (local->tim_in_locked_section) {
+               __ieee80211_beacon_add_tim(sdata, ps, skb);
+       } else {
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->tim_lock, flags);
+               __ieee80211_beacon_add_tim(sdata, ps, skb);
+               spin_unlock_irqrestore(&local->tim_lock, flags);
+       }
+
+       return 0;
+}
+
 struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                                         struct ieee80211_vif *vif,
                                         u16 *tim_offset, u16 *tim_length)
@@ -2372,22 +2396,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                        memcpy(skb_put(skb, beacon->head_len), beacon->head,
                               beacon->head_len);
 
-                       /*
-                        * Not very nice, but we want to allow the driver to call
-                        * ieee80211_beacon_get() as a response to the set_tim()
-                        * callback. That, however, is already invoked under the
-                        * sta_lock to guarantee consistent and race-free update
-                        * of the tim bitmap in mac80211 and the driver.
-                        */
-                       if (local->tim_in_locked_section) {
-                               ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
-                       } else {
-                               unsigned long flags;
-
-                               spin_lock_irqsave(&local->tim_lock, flags);
-                               ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
-                               spin_unlock_irqrestore(&local->tim_lock, flags);
-                       }
+                       ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
 
                        if (tim_offset)
                                *tim_offset = beacon->head_len;
index f11e8c540db41b71a310c1717c54a4e2278d9c4b..7519018ff71af2844241f43697a1926f54122def 100644 (file)
@@ -1358,6 +1358,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        struct ieee80211_chanctx *ctx;
        struct sta_info *sta;
        int res, i;
+       bool reconfig_due_to_wowlan = false;
 
 #ifdef CONFIG_PM
        if (local->suspended)
@@ -1377,6 +1378,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                 * res is 1, which means the driver requested
                 * to go through a regular reset on wakeup.
                 */
+               reconfig_due_to_wowlan = true;
        }
 #endif
        /* everything else happens only if HW was up & running */
@@ -1526,6 +1528,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_IDLE |
                          BSS_CHANGED_TXPOWER;
 
+#ifdef CONFIG_PM
+               if (local->resuming && !reconfig_due_to_wowlan)
+                       sdata->vif.bss_conf = sdata->suspend_bss_conf;
+#endif
+
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        changed |= BSS_CHANGED_ASSOC |
@@ -1550,9 +1557,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
                        /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
-                       changed |= BSS_CHANGED_BEACON |
-                                  BSS_CHANGED_BEACON_ENABLED;
-                       ieee80211_bss_info_change_notify(sdata, changed);
+                       if (sdata->vif.bss_conf.enable_beacon) {
+                               changed |= BSS_CHANGED_BEACON |
+                                          BSS_CHANGED_BEACON_ENABLED;
+                               ieee80211_bss_info_change_notify(sdata, changed);
+                       }
                        break;
                case NL80211_IFTYPE_WDS:
                        break;
@@ -1632,7 +1641,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                mutex_lock(&local->sta_mtx);
 
                list_for_each_entry(sta, &local->sta_list, list) {
-                       ieee80211_sta_tear_down_BA_sessions(sta, true);
+                       ieee80211_sta_tear_down_BA_sessions(
+                                       sta, AGG_STOP_LOCAL_REQUEST);
                        clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
                }
 
@@ -1646,10 +1656,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
         * If this is for hw restart things are still running.
         * We may want to change that later, however.
         */
-       if (!local->suspended) {
+       if (!local->suspended || reconfig_due_to_wowlan)
                drv_restart_complete(local);
+
+       if (!local->suspended)
                return 0;
-       }
 
 #ifdef CONFIG_PM
        /* first set suspended false, then resuming */
@@ -1864,7 +1875,7 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
 }
 
 u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
-                                                          u32 cap)
+                              u32 cap)
 {
        __le32 tmp;
 
index 49e96df5fbc4b38e842540f65c5b23309440c597..eb2c8ebf6d9930ef650ec8e9a12178e89cfb2199 100644 (file)
@@ -124,6 +124,12 @@ config NF_CONNTRACK_TIMESTAMP
 
          If unsure, say `N'.
 
+config NF_CONNTRACK_LABELS
+       bool
+       help
+         This option enables support for assigning user-defined flag bits
+         to connection tracking entries.  It selected by the connlabel match.
+
 config NF_CT_PROTO_DCCP
        tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)'
        depends on EXPERIMENTAL
@@ -805,6 +811,15 @@ config NETFILTER_XT_MATCH_ADDRTYPE
          If you want to compile it as a module, say M here and read
          <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_BPF
+       tristate '"bpf" match support'
+       depends on NETFILTER_ADVANCED
+       help
+         BPF matching applies a linux socket filter to each packet and
+         accepts those for which the filter returns non-zero.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_CLUSTER
        tristate '"cluster" match support'
        depends on NF_CONNTRACK
@@ -842,6 +857,18 @@ config NETFILTER_XT_MATCH_CONNBYTES
          If you want to compile it as a module, say M here and read
          <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_CONNLABEL
+       tristate '"connlabel" match support'
+       select NF_CONNTRACK_LABELS
+       depends on NETFILTER_ADVANCED
+       ---help---
+         This match allows you to test and assign userspace-defined labels names
+         to a connection.  The kernel only stores bit values - mapping
+         names to bits is done by userspace.
+
+         Unlike connmark, more than 32 flag bits may be assigned to a
+         connection simultaneously.
+
 config NETFILTER_XT_MATCH_CONNLIMIT
        tristate '"connlimit" match support"'
        depends on NF_CONNTRACK
index 32596978df1d9bb0b92f1b0b1b81c4adf7204c94..a1abf87d43bfbd902f82cc9f8aae156d936cd89a 100644 (file)
@@ -4,6 +4,7 @@ nf_conntrack-y  := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp
 nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
 nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
 nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
+nf_conntrack-$(CONFIG_NF_CONNTRACK_LABELS) += nf_conntrack_labels.o
 
 obj-$(CONFIG_NETFILTER) = netfilter.o
 
@@ -98,9 +99,11 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o
 
 # matches
 obj-$(CONFIG_NETFILTER_XT_MATCH_ADDRTYPE) += xt_addrtype.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_BPF) += xt_bpf.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLABEL) += xt_connlabel.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o
index 7df424e2d10cf6146e7c3b38eaf0bf86a2bb0544..2d3030ab5b619c1a354ec328acf2e85bfd6fd250 100644 (file)
@@ -106,36 +106,26 @@ static void nf_conntrack_acct_fini_sysctl(struct net *net)
 }
 #endif
 
-int nf_conntrack_acct_init(struct net *net)
+int nf_conntrack_acct_pernet_init(struct net *net)
 {
-       int ret;
-
        net->ct.sysctl_acct = nf_ct_acct;
+       return nf_conntrack_acct_init_sysctl(net);
+}
 
-       if (net_eq(net, &init_net)) {
-               ret = nf_ct_extend_register(&acct_extend);
-               if (ret < 0) {
-                       printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n");
-                       goto out_extend_register;
-               }
-       }
+void nf_conntrack_acct_pernet_fini(struct net *net)
+{
+       nf_conntrack_acct_fini_sysctl(net);
+}
 
-       ret = nf_conntrack_acct_init_sysctl(net);
+int nf_conntrack_acct_init(void)
+{
+       int ret = nf_ct_extend_register(&acct_extend);
        if (ret < 0)
-               goto out_sysctl;
-
-       return 0;
-
-out_sysctl:
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&acct_extend);
-out_extend_register:
+               pr_err("nf_conntrack_acct: Unable to register extension\n");
        return ret;
 }
 
-void nf_conntrack_acct_fini(struct net *net)
+void nf_conntrack_acct_fini(void)
 {
-       nf_conntrack_acct_fini_sysctl(net);
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&acct_extend);
+       nf_ct_extend_unregister(&acct_extend);
 }
index e4a0c4fb3a7cef64d1f15c9173d5a3e62ad616b4..c8e001a9c45b15a8fe4038845f2111c6470c67b7 100644 (file)
@@ -45,6 +45,7 @@
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/nf_conntrack_timestamp.h>
 #include <net/netfilter/nf_conntrack_timeout.h>
+#include <net/netfilter/nf_conntrack_labels.h>
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_core.h>
 
@@ -763,6 +764,7 @@ void nf_conntrack_free(struct nf_conn *ct)
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_free);
 
+
 /* Allocate a new conntrack: we return -ENOMEM if classification
    failed due to stress.  Otherwise it really is unclassifiable. */
 static struct nf_conntrack_tuple_hash *
@@ -809,6 +811,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
 
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
        nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
+       nf_ct_labels_ext_add(ct);
 
        ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL;
        nf_ct_ecache_ext_add(ct, ecache ? ecache->ctmask : 0,
@@ -1331,18 +1334,42 @@ static int untrack_refs(void)
        return cnt;
 }
 
-static void nf_conntrack_cleanup_init_net(void)
+void nf_conntrack_cleanup_start(void)
+{
+       RCU_INIT_POINTER(ip_ct_attach, NULL);
+}
+
+void nf_conntrack_cleanup_end(void)
 {
+       RCU_INIT_POINTER(nf_ct_destroy, NULL);
        while (untrack_refs() > 0)
                schedule();
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        nf_ct_extend_unregister(&nf_ct_zone_extend);
 #endif
+       nf_conntrack_proto_fini();
+       nf_conntrack_labels_fini();
+       nf_conntrack_helper_fini();
+       nf_conntrack_timeout_fini();
+       nf_conntrack_ecache_fini();
+       nf_conntrack_tstamp_fini();
+       nf_conntrack_acct_fini();
+       nf_conntrack_expect_fini();
 }
 
-static void nf_conntrack_cleanup_net(struct net *net)
+/*
+ * Mishearing the voices in his head, our hero wonders how he's
+ * supposed to kill the mall.
+ */
+void nf_conntrack_cleanup_net(struct net *net)
 {
+       /*
+        * This makes sure all current packets have passed through
+        *  netfilter framework.  Roll on, two-stage module
+        *  delete...
+        */
+       synchronize_net();
  i_see_dead_people:
        nf_ct_iterate_cleanup(net, kill_all, NULL);
        nf_ct_release_dying_list(net);
@@ -1352,38 +1379,17 @@ static void nf_conntrack_cleanup_net(struct net *net)
        }
 
        nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
-       nf_conntrack_helper_fini(net);
-       nf_conntrack_timeout_fini(net);
-       nf_conntrack_ecache_fini(net);
-       nf_conntrack_tstamp_fini(net);
-       nf_conntrack_acct_fini(net);
-       nf_conntrack_expect_fini(net);
+       nf_conntrack_proto_pernet_fini(net);
+       nf_conntrack_helper_pernet_fini(net);
+       nf_conntrack_ecache_pernet_fini(net);
+       nf_conntrack_tstamp_pernet_fini(net);
+       nf_conntrack_acct_pernet_fini(net);
+       nf_conntrack_expect_pernet_fini(net);
        kmem_cache_destroy(net->ct.nf_conntrack_cachep);
        kfree(net->ct.slabname);
        free_percpu(net->ct.stat);
 }
 
-/* Mishearing the voices in his head, our hero wonders how he's
-   supposed to kill the mall. */
-void nf_conntrack_cleanup(struct net *net)
-{
-       if (net_eq(net, &init_net))
-               RCU_INIT_POINTER(ip_ct_attach, NULL);
-
-       /* This makes sure all current packets have passed through
-          netfilter framework.  Roll on, two-stage module
-          delete... */
-       synchronize_net();
-       nf_conntrack_proto_fini(net);
-       nf_conntrack_cleanup_net(net);
-}
-
-void nf_conntrack_cleanup_end(void)
-{
-       RCU_INIT_POINTER(nf_ct_destroy, NULL);
-       nf_conntrack_cleanup_init_net();
-}
-
 void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
 {
        struct hlist_nulls_head *hash;
@@ -1474,7 +1480,7 @@ void nf_ct_untracked_status_or(unsigned long bits)
 }
 EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
 
-static int nf_conntrack_init_init_net(void)
+int nf_conntrack_init_start(void)
 {
        int max_factor = 8;
        int ret, cpu;
@@ -1501,11 +1507,44 @@ static int nf_conntrack_init_init_net(void)
        printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n",
               NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
               nf_conntrack_max);
+
+       ret = nf_conntrack_expect_init();
+       if (ret < 0)
+               goto err_expect;
+
+       ret = nf_conntrack_acct_init();
+       if (ret < 0)
+               goto err_acct;
+
+       ret = nf_conntrack_tstamp_init();
+       if (ret < 0)
+               goto err_tstamp;
+
+       ret = nf_conntrack_ecache_init();
+       if (ret < 0)
+               goto err_ecache;
+
+       ret = nf_conntrack_timeout_init();
+       if (ret < 0)
+               goto err_timeout;
+
+       ret = nf_conntrack_helper_init();
+       if (ret < 0)
+               goto err_helper;
+
+       ret = nf_conntrack_labels_init();
+       if (ret < 0)
+               goto err_labels;
+
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        ret = nf_ct_extend_register(&nf_ct_zone_extend);
        if (ret < 0)
                goto err_extend;
 #endif
+       ret = nf_conntrack_proto_init();
+       if (ret < 0)
+               goto err_proto;
+
        /* Set up fake conntrack: to never be deleted, not in any hashes */
        for_each_possible_cpu(cpu) {
                struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
@@ -1516,12 +1555,38 @@ static int nf_conntrack_init_init_net(void)
        nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
        return 0;
 
+err_proto:
 #ifdef CONFIG_NF_CONNTRACK_ZONES
+       nf_ct_extend_unregister(&nf_ct_zone_extend);
 err_extend:
 #endif
+       nf_conntrack_labels_fini();
+err_labels:
+       nf_conntrack_helper_fini();
+err_helper:
+       nf_conntrack_timeout_fini();
+err_timeout:
+       nf_conntrack_ecache_fini();
+err_ecache:
+       nf_conntrack_tstamp_fini();
+err_tstamp:
+       nf_conntrack_acct_fini();
+err_acct:
+       nf_conntrack_expect_fini();
+err_expect:
        return ret;
 }
 
+void nf_conntrack_init_end(void)
+{
+       /* For use by REJECT target */
+       RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
+       RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
+
+       /* Howto get NAT offsets */
+       RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
+}
+
 /*
  * We need to use special "null" values, not used in hash table
  */
@@ -1529,7 +1594,7 @@ err_extend:
 #define DYING_NULLS_VAL                ((1<<30)+1)
 #define TEMPLATE_NULLS_VAL     ((1<<30)+2)
 
-static int nf_conntrack_init_net(struct net *net)
+int nf_conntrack_init_net(struct net *net)
 {
        int ret;
 
@@ -1565,35 +1630,36 @@ static int nf_conntrack_init_net(struct net *net)
                printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
                goto err_hash;
        }
-       ret = nf_conntrack_expect_init(net);
+       ret = nf_conntrack_expect_pernet_init(net);
        if (ret < 0)
                goto err_expect;
-       ret = nf_conntrack_acct_init(net);
+       ret = nf_conntrack_acct_pernet_init(net);
        if (ret < 0)
                goto err_acct;
-       ret = nf_conntrack_tstamp_init(net);
+       ret = nf_conntrack_tstamp_pernet_init(net);
        if (ret < 0)
                goto err_tstamp;
-       ret = nf_conntrack_ecache_init(net);
+       ret = nf_conntrack_ecache_pernet_init(net);
        if (ret < 0)
                goto err_ecache;
-       ret = nf_conntrack_timeout_init(net);
-       if (ret < 0)
-               goto err_timeout;
-       ret = nf_conntrack_helper_init(net);
+       ret = nf_conntrack_helper_pernet_init(net);
        if (ret < 0)
                goto err_helper;
+       ret = nf_conntrack_proto_pernet_init(net);
+       if (ret < 0)
+               goto err_proto;
        return 0;
+
+err_proto:
+       nf_conntrack_helper_pernet_fini(net);
 err_helper:
-       nf_conntrack_timeout_fini(net);
-err_timeout:
-       nf_conntrack_ecache_fini(net);
+       nf_conntrack_ecache_pernet_fini(net);
 err_ecache:
-       nf_conntrack_tstamp_fini(net);
+       nf_conntrack_tstamp_pernet_fini(net);
 err_tstamp:
-       nf_conntrack_acct_fini(net);
+       nf_conntrack_acct_pernet_fini(net);
 err_acct:
-       nf_conntrack_expect_fini(net);
+       nf_conntrack_expect_pernet_fini(net);
 err_expect:
        nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
 err_hash:
@@ -1610,38 +1676,3 @@ s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
                        enum ip_conntrack_dir dir,
                        u32 seq);
 EXPORT_SYMBOL_GPL(nf_ct_nat_offset);
-
-int nf_conntrack_init(struct net *net)
-{
-       int ret;
-
-       if (net_eq(net, &init_net)) {
-               ret = nf_conntrack_init_init_net();
-               if (ret < 0)
-                       goto out_init_net;
-       }
-       ret = nf_conntrack_proto_init(net);
-       if (ret < 0)
-               goto out_proto;
-       ret = nf_conntrack_init_net(net);
-       if (ret < 0)
-               goto out_net;
-
-       if (net_eq(net, &init_net)) {
-               /* For use by REJECT target */
-               RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
-               RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
-
-               /* Howto get NAT offsets */
-               RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
-       }
-       return 0;
-
-out_net:
-       nf_conntrack_proto_fini(net);
-out_proto:
-       if (net_eq(net, &init_net))
-               nf_conntrack_cleanup_init_net();
-out_init_net:
-       return ret;
-}
index faa978f1714b831ff81d81e9ec4732eb3f167fb7..b5d2eb8bf0d58f98f2d9ea3a4e467e8b2861a7cf 100644 (file)
@@ -233,38 +233,27 @@ static void nf_conntrack_event_fini_sysctl(struct net *net)
 }
 #endif /* CONFIG_SYSCTL */
 
-int nf_conntrack_ecache_init(struct net *net)
+int nf_conntrack_ecache_pernet_init(struct net *net)
 {
-       int ret;
-
        net->ct.sysctl_events = nf_ct_events;
        net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout;
+       return nf_conntrack_event_init_sysctl(net);
+}
 
-       if (net_eq(net, &init_net)) {
-               ret = nf_ct_extend_register(&event_extend);
-               if (ret < 0) {
-                       printk(KERN_ERR "nf_ct_event: Unable to register "
-                                       "event extension.\n");
-                       goto out_extend_register;
-               }
-       }
+void nf_conntrack_ecache_pernet_fini(struct net *net)
+{
+       nf_conntrack_event_fini_sysctl(net);
+}
 
-       ret = nf_conntrack_event_init_sysctl(net);
+int nf_conntrack_ecache_init(void)
+{
+       int ret = nf_ct_extend_register(&event_extend);
        if (ret < 0)
-               goto out_sysctl;
-
-       return 0;
-
-out_sysctl:
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&event_extend);
-out_extend_register:
+               pr_err("nf_ct_event: Unable to register event extension.\n");
        return ret;
 }
 
-void nf_conntrack_ecache_fini(struct net *net)
+void nf_conntrack_ecache_fini(void)
 {
-       nf_conntrack_event_fini_sysctl(net);
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&event_extend);
+       nf_ct_extend_unregister(&event_extend);
 }
index 527651a53a45ded66c97162f4e072ca55a7d1efa..bdd341899ed3f933a3b124e8d6a04e8c4100796a 100644 (file)
@@ -587,53 +587,50 @@ static void exp_proc_remove(struct net *net)
 
 module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400);
 
-int nf_conntrack_expect_init(struct net *net)
+int nf_conntrack_expect_pernet_init(struct net *net)
 {
        int err = -ENOMEM;
 
-       if (net_eq(net, &init_net)) {
-               if (!nf_ct_expect_hsize) {
-                       nf_ct_expect_hsize = net->ct.htable_size / 256;
-                       if (!nf_ct_expect_hsize)
-                               nf_ct_expect_hsize = 1;
-               }
-               nf_ct_expect_max = nf_ct_expect_hsize * 4;
-       }
-
        net->ct.expect_count = 0;
        net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0);
        if (net->ct.expect_hash == NULL)
                goto err1;
 
-       if (net_eq(net, &init_net)) {
-               nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
-                                       sizeof(struct nf_conntrack_expect),
-                                       0, 0, NULL);
-               if (!nf_ct_expect_cachep)
-                       goto err2;
-       }
-
        err = exp_proc_init(net);
        if (err < 0)
-               goto err3;
+               goto err2;
 
        return 0;
-
-err3:
-       if (net_eq(net, &init_net))
-               kmem_cache_destroy(nf_ct_expect_cachep);
 err2:
        nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize);
 err1:
        return err;
 }
 
-void nf_conntrack_expect_fini(struct net *net)
+void nf_conntrack_expect_pernet_fini(struct net *net)
 {
        exp_proc_remove(net);
-       if (net_eq(net, &init_net)) {
-               rcu_barrier(); /* Wait for call_rcu() before destroy */
-               kmem_cache_destroy(nf_ct_expect_cachep);
-       }
        nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize);
 }
+
+int nf_conntrack_expect_init(void)
+{
+       if (!nf_ct_expect_hsize) {
+               nf_ct_expect_hsize = nf_conntrack_htable_size / 256;
+               if (!nf_ct_expect_hsize)
+                       nf_ct_expect_hsize = 1;
+       }
+       nf_ct_expect_max = nf_ct_expect_hsize * 4;
+       nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
+                               sizeof(struct nf_conntrack_expect),
+                               0, 0, NULL);
+       if (!nf_ct_expect_cachep)
+               return -ENOMEM;
+       return 0;
+}
+
+void nf_conntrack_expect_fini(void)
+{
+       rcu_barrier(); /* Wait for call_rcu() before destroy */
+       kmem_cache_destroy(nf_ct_expect_cachep);
+}
index 884f2b39319a258ffbaa4360736fd7f83b867195..2f380f73c4c09cc54b70fde2686baabb90507f87 100644 (file)
@@ -423,44 +423,41 @@ static struct nf_ct_ext_type helper_extend __read_mostly = {
        .id     = NF_CT_EXT_HELPER,
 };
 
-int nf_conntrack_helper_init(struct net *net)
+int nf_conntrack_helper_pernet_init(struct net *net)
 {
-       int err;
-
        net->ct.auto_assign_helper_warned = false;
        net->ct.sysctl_auto_assign_helper = nf_ct_auto_assign_helper;
+       return nf_conntrack_helper_init_sysctl(net);
+}
 
-       if (net_eq(net, &init_net)) {
-               nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
-               nf_ct_helper_hash =
-                       nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
-               if (!nf_ct_helper_hash)
-                       return -ENOMEM;
+void nf_conntrack_helper_pernet_fini(struct net *net)
+{
+       nf_conntrack_helper_fini_sysctl(net);
+}
 
-               err = nf_ct_extend_register(&helper_extend);
-               if (err < 0)
-                       goto err1;
+int nf_conntrack_helper_init(void)
+{
+       int ret;
+       nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
+       nf_ct_helper_hash =
+               nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
+       if (!nf_ct_helper_hash)
+               return -ENOMEM;
+
+       ret = nf_ct_extend_register(&helper_extend);
+       if (ret < 0) {
+               pr_err("nf_ct_helper: Unable to register helper extension.\n");
+               goto out_extend;
        }
 
-       err = nf_conntrack_helper_init_sysctl(net);
-       if (err < 0)
-               goto out_sysctl;
-
        return 0;
-
-out_sysctl:
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&helper_extend);
-err1:
+out_extend:
        nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize);
-       return err;
+       return ret;
 }
 
-void nf_conntrack_helper_fini(struct net *net)
+void nf_conntrack_helper_fini(void)
 {
-       nf_conntrack_helper_fini_sysctl(net);
-       if (net_eq(net, &init_net)) {
-               nf_ct_extend_unregister(&helper_extend);
-               nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize);
-       }
+       nf_ct_extend_unregister(&helper_extend);
+       nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize);
 }
diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c
new file mode 100644 (file)
index 0000000..8fe2e99
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * test/set flag bits stored in conntrack extension area.
+ *
+ * (C) 2013 Astaro GmbH & Co KG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ctype.h>
+#include <linux/export.h>
+#include <linux/jhash.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_labels.h>
+
+static unsigned int label_bits(const struct nf_conn_labels *l)
+{
+       unsigned int longs = l->words;
+       return longs * BITS_PER_LONG;
+}
+
+bool nf_connlabel_match(const struct nf_conn *ct, u16 bit)
+{
+       struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+       if (!labels)
+               return false;
+
+       return bit < label_bits(labels) && test_bit(bit, labels->bits);
+}
+EXPORT_SYMBOL_GPL(nf_connlabel_match);
+
+int nf_connlabel_set(struct nf_conn *ct, u16 bit)
+{
+       struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+       if (!labels || bit >= label_bits(labels))
+               return -ENOSPC;
+
+       if (test_bit(bit, labels->bits))
+               return 0;
+
+       if (test_and_set_bit(bit, labels->bits))
+               nf_conntrack_event_cache(IPCT_LABEL, ct);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nf_connlabel_set);
+
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
+static void replace_u32(u32 *address, u32 mask, u32 new)
+{
+       u32 old, tmp;
+
+       do {
+               old = *address;
+               tmp = (old & mask) ^ new;
+       } while (cmpxchg(address, old, tmp) != old);
+}
+
+int nf_connlabels_replace(struct nf_conn *ct,
+                         const u32 *data,
+                         const u32 *mask, unsigned int words32)
+{
+       struct nf_conn_labels *labels;
+       unsigned int size, i;
+       u32 *dst;
+
+       labels = nf_ct_labels_find(ct);
+       if (!labels)
+               return -ENOSPC;
+
+       size = labels->words * sizeof(long);
+       if (size < (words32 * sizeof(u32)))
+               words32 = size / sizeof(u32);
+
+       dst = (u32 *) labels->bits;
+       if (words32) {
+               for (i = 0; i < words32; i++)
+                       replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
+       }
+
+       size /= sizeof(u32);
+       for (i = words32; i < size; i++) /* pad */
+               replace_u32(&dst[i], 0, 0);
+
+       nf_conntrack_event_cache(IPCT_LABEL, ct);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nf_connlabels_replace);
+#endif
+
+static struct nf_ct_ext_type labels_extend __read_mostly = {
+       .len    = sizeof(struct nf_conn_labels),
+       .align  = __alignof__(struct nf_conn_labels),
+       .id     = NF_CT_EXT_LABELS,
+};
+
+int nf_conntrack_labels_init(void)
+{
+       return nf_ct_extend_register(&labels_extend);
+}
+
+void nf_conntrack_labels_fini(void)
+{
+       nf_ct_extend_unregister(&labels_extend);
+}
index 627b0e50b2389120e86ed107a3af01d690e07a29..2334cc5d2b16ec3b95284458a9126655a9aea91b 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/netfilter/nf_conntrack_acct.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/nf_conntrack_timestamp.h>
+#include <net/netfilter/nf_conntrack_labels.h>
 #ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_core.h>
 #include <net/netfilter/nf_nat_l4proto.h>
@@ -323,6 +324,40 @@ nla_put_failure:
 #define ctnetlink_dump_secctx(a, b) (0)
 #endif
 
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+static int ctnetlink_label_size(const struct nf_conn *ct)
+{
+       struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+       if (!labels)
+               return 0;
+       return nla_total_size(labels->words * sizeof(long));
+}
+
+static int
+ctnetlink_dump_labels(struct sk_buff *skb, const struct nf_conn *ct)
+{
+       struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+       unsigned int len, i;
+
+       if (!labels)
+               return 0;
+
+       len = labels->words * sizeof(long);
+       i = 0;
+       do {
+               if (labels->bits[i] != 0)
+                       return nla_put(skb, CTA_LABELS, len, labels->bits);
+               i++;
+       } while (i < labels->words);
+
+       return 0;
+}
+#else
+#define ctnetlink_dump_labels(a, b) (0)
+#define ctnetlink_label_size(a)        (0)
+#endif
+
 #define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
 
 static inline int
@@ -463,6 +498,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
            ctnetlink_dump_helpinfo(skb, ct) < 0 ||
            ctnetlink_dump_mark(skb, ct) < 0 ||
            ctnetlink_dump_secctx(skb, ct) < 0 ||
+           ctnetlink_dump_labels(skb, ct) < 0 ||
            ctnetlink_dump_id(skb, ct) < 0 ||
            ctnetlink_dump_use(skb, ct) < 0 ||
            ctnetlink_dump_master(skb, ct) < 0 ||
@@ -561,6 +597,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
               + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
 #endif
               + ctnetlink_proto_size(ct)
+              + ctnetlink_label_size(ct)
               ;
 }
 
@@ -662,6 +699,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
                    && ctnetlink_dump_secctx(skb, ct) < 0)
                        goto nla_put_failure;
 #endif
+               if (events & (1 << IPCT_LABEL) &&
+                    ctnetlink_dump_labels(skb, ct) < 0)
+                       goto nla_put_failure;
 
                if (events & (1 << IPCT_RELATED) &&
                    ctnetlink_dump_master(skb, ct) < 0)
@@ -921,6 +961,7 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name,
        return 0;
 }
 
+#define __CTA_LABELS_MAX_LENGTH ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
 static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_TUPLE_ORIG]        = { .type = NLA_NESTED },
        [CTA_TUPLE_REPLY]       = { .type = NLA_NESTED },
@@ -937,6 +978,10 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_NAT_SEQ_ADJ_REPLY] = { .type = NLA_NESTED },
        [CTA_ZONE]              = { .type = NLA_U16 },
        [CTA_MARK_MASK]         = { .type = NLA_U32 },
+       [CTA_LABELS]            = { .type = NLA_BINARY,
+                                   .len = __CTA_LABELS_MAX_LENGTH },
+       [CTA_LABELS_MASK]       = { .type = NLA_BINARY,
+                                   .len = __CTA_LABELS_MAX_LENGTH },
 };
 
 static int
@@ -1464,6 +1509,31 @@ ctnetlink_change_nat_seq_adj(struct nf_conn *ct,
 }
 #endif
 
+static int
+ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[])
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       size_t len = nla_len(cda[CTA_LABELS]);
+       const void *mask = cda[CTA_LABELS_MASK];
+
+       if (len & (sizeof(u32)-1)) /* must be multiple of u32 */
+               return -EINVAL;
+
+       if (mask) {
+               if (nla_len(cda[CTA_LABELS_MASK]) == 0 ||
+                   nla_len(cda[CTA_LABELS_MASK]) != len)
+                       return -EINVAL;
+               mask = nla_data(cda[CTA_LABELS_MASK]);
+       }
+
+       len /= sizeof(u32);
+
+       return nf_connlabels_replace(ct, nla_data(cda[CTA_LABELS]), mask, len);
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
 static int
 ctnetlink_change_conntrack(struct nf_conn *ct,
                           const struct nlattr * const cda[])
@@ -1510,6 +1580,11 @@ ctnetlink_change_conntrack(struct nf_conn *ct,
                        return err;
        }
 #endif
+       if (cda[CTA_LABELS]) {
+               err = ctnetlink_attach_labels(ct, cda);
+               if (err < 0)
+                       return err;
+       }
 
        return 0;
 }
@@ -1598,6 +1673,8 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
        nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
        nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
+       nf_ct_labels_ext_add(ct);
+
        /* we must add conntrack extensions before confirmation. */
        ct->status |= IPS_CONFIRMED;
 
@@ -1716,6 +1793,10 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
                        else
                                events = IPCT_NEW;
 
+                       if (cda[CTA_LABELS] &&
+                           ctnetlink_attach_labels(ct, cda) == 0)
+                               events |= (1 << IPCT_LABEL);
+
                        nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
                                                      (1 << IPCT_ASSURED) |
                                                      (1 << IPCT_HELPER) |
@@ -1983,6 +2064,8 @@ ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
        if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
                goto nla_put_failure;
 #endif
+       if (ctnetlink_dump_labels(skb, ct) < 0)
+               goto nla_put_failure;
        rcu_read_unlock();
        return 0;
 
@@ -2011,6 +2094,11 @@ ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
                if (err < 0)
                        return err;
        }
+       if (cda[CTA_LABELS]) {
+               err = ctnetlink_attach_labels(ct, cda);
+               if (err < 0)
+                       return err;
+       }
 #if defined(CONFIG_NF_CONNTRACK_MARK)
        if (cda[CTA_MARK])
                ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
index 51e928db48c846f469da93ed70ed072807f3359f..58ab4050830cbadc5e1b817ea600f60bacff29d0 100644 (file)
@@ -212,8 +212,7 @@ static void nf_ct_l3proto_unregister_sysctl(struct net *net,
 #endif
 }
 
-static int
-nf_conntrack_l3proto_register_net(struct nf_conntrack_l3proto *proto)
+int nf_ct_l3proto_register(struct nf_conntrack_l3proto *proto)
 {
        int ret = 0;
        struct nf_conntrack_l3proto *old;
@@ -242,8 +241,9 @@ out_unlock:
        return ret;
 
 }
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_register);
 
-int nf_conntrack_l3proto_register(struct net *net,
+int nf_ct_l3proto_pernet_register(struct net *net,
                                  struct nf_conntrack_l3proto *proto)
 {
        int ret = 0;
@@ -254,22 +254,11 @@ int nf_conntrack_l3proto_register(struct net *net,
                        return ret;
        }
 
-       ret = nf_ct_l3proto_register_sysctl(net, proto);
-       if (ret < 0)
-               return ret;
-
-       if (net == &init_net) {
-               ret = nf_conntrack_l3proto_register_net(proto);
-               if (ret < 0)
-                       nf_ct_l3proto_unregister_sysctl(net, proto);
-       }
-
-       return ret;
+       return nf_ct_l3proto_register_sysctl(net, proto);
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_register);
 
-static void
-nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto)
+void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto)
 {
        BUG_ON(proto->l3proto >= AF_MAX);
 
@@ -283,19 +272,17 @@ nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto)
 
        synchronize_rcu();
 }
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_unregister);
 
-void nf_conntrack_l3proto_unregister(struct net *net,
+void nf_ct_l3proto_pernet_unregister(struct net *net,
                                     struct nf_conntrack_l3proto *proto)
 {
-       if (net == &init_net)
-               nf_conntrack_l3proto_unregister_net(proto);
-
        nf_ct_l3proto_unregister_sysctl(net, proto);
 
        /* Remove all contrack entries for this protocol */
        nf_ct_iterate_cleanup(net, kill_l3proto, proto);
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_unregister);
 
 static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
                                              struct nf_conntrack_l4proto *l4proto)
@@ -376,8 +363,7 @@ void nf_ct_l4proto_unregister_sysctl(struct net *net,
 
 /* FIXME: Allow NULL functions and sub in pointers to generic for
    them. --RR */
-static int
-nf_conntrack_l4proto_register_net(struct nf_conntrack_l4proto *l4proto)
+int nf_ct_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 {
        int ret = 0;
 
@@ -431,8 +417,9 @@ out_unlock:
        mutex_unlock(&nf_ct_proto_mutex);
        return ret;
 }
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_register);
 
-int nf_conntrack_l4proto_register(struct net *net,
+int nf_ct_l4proto_pernet_register(struct net *net,
                                  struct nf_conntrack_l4proto *l4proto)
 {
        int ret = 0;
@@ -452,22 +439,13 @@ int nf_conntrack_l4proto_register(struct net *net,
        if (ret < 0)
                goto out;
 
-       if (net == &init_net) {
-               ret = nf_conntrack_l4proto_register_net(l4proto);
-               if (ret < 0) {
-                       nf_ct_l4proto_unregister_sysctl(net, pn, l4proto);
-                       goto out;
-               }
-       }
-
        pn->users++;
 out:
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register);
 
-static void
-nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto)
+void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
 {
        BUG_ON(l4proto->l3proto >= PF_MAX);
 
@@ -482,15 +460,13 @@ nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto)
 
        synchronize_rcu();
 }
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister);
 
-void nf_conntrack_l4proto_unregister(struct net *net,
+void nf_ct_l4proto_pernet_unregister(struct net *net,
                                     struct nf_conntrack_l4proto *l4proto)
 {
        struct nf_proto_net *pn = NULL;
 
-       if (net == &init_net)
-               nf_conntrack_l4proto_unregister_net(l4proto);
-
        pn = nf_ct_l4proto_net(net, l4proto);
        if (pn == NULL)
                return;
@@ -501,11 +477,10 @@ void nf_conntrack_l4proto_unregister(struct net *net,
        /* Remove all contrack entries for this protocol */
        nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister);
 
-int nf_conntrack_proto_init(struct net *net)
+int nf_conntrack_proto_pernet_init(struct net *net)
 {
-       unsigned int i;
        int err;
        struct nf_proto_net *pn = nf_ct_l4proto_net(net,
                                        &nf_conntrack_l4proto_generic);
@@ -520,19 +495,12 @@ int nf_conntrack_proto_init(struct net *net)
        if (err < 0)
                return err;
 
-       if (net == &init_net) {
-               for (i = 0; i < AF_MAX; i++)
-                       rcu_assign_pointer(nf_ct_l3protos[i],
-                                          &nf_conntrack_l3proto_generic);
-       }
-
        pn->users++;
        return 0;
 }
 
-void nf_conntrack_proto_fini(struct net *net)
+void nf_conntrack_proto_pernet_fini(struct net *net)
 {
-       unsigned int i;
        struct nf_proto_net *pn = nf_ct_l4proto_net(net,
                                        &nf_conntrack_l4proto_generic);
 
@@ -540,9 +508,21 @@ void nf_conntrack_proto_fini(struct net *net)
        nf_ct_l4proto_unregister_sysctl(net,
                                        pn,
                                        &nf_conntrack_l4proto_generic);
-       if (net == &init_net) {
-               /* free l3proto protocol tables */
-               for (i = 0; i < PF_MAX; i++)
-                       kfree(nf_ct_protos[i]);
-       }
+}
+
+int nf_conntrack_proto_init(void)
+{
+       unsigned int i;
+       for (i = 0; i < AF_MAX; i++)
+               rcu_assign_pointer(nf_ct_l3protos[i],
+                                  &nf_conntrack_l3proto_generic);
+       return 0;
+}
+
+void nf_conntrack_proto_fini(void)
+{
+       unsigned int i;
+       /* free l3proto protocol tables */
+       for (i = 0; i < PF_MAX; i++)
+               kfree(nf_ct_protos[i]);
 }
index a8ae287bc7afe00ec89ed8032f3cbd7ea1c54b7a..432f95780003f2e36a4d0fb08aaa10b900e052ff 100644 (file)
@@ -935,32 +935,27 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
 static __net_init int dccp_net_init(struct net *net)
 {
        int ret = 0;
-       ret = nf_conntrack_l4proto_register(net,
-                                           &dccp_proto4);
+       ret = nf_ct_l4proto_pernet_register(net, &dccp_proto4);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_dccp4 :protocol register failed.\n");
+               pr_err("nf_conntrack_dccp4: pernet registration failed.\n");
                goto out;
        }
-       ret = nf_conntrack_l4proto_register(net,
-                                           &dccp_proto6);
+       ret = nf_ct_l4proto_pernet_register(net, &dccp_proto6);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_dccp6 :protocol register failed.\n");
+               pr_err("nf_conntrack_dccp6: pernet registration failed.\n");
                goto cleanup_dccp4;
        }
        return 0;
 cleanup_dccp4:
-       nf_conntrack_l4proto_unregister(net,
-                                       &dccp_proto4);
+       nf_ct_l4proto_pernet_unregister(net, &dccp_proto4);
 out:
        return ret;
 }
 
 static __net_exit void dccp_net_exit(struct net *net)
 {
-       nf_conntrack_l4proto_unregister(net,
-                                       &dccp_proto6);
-       nf_conntrack_l4proto_unregister(net,
-                                       &dccp_proto4);
+       nf_ct_l4proto_pernet_unregister(net, &dccp_proto6);
+       nf_ct_l4proto_pernet_unregister(net, &dccp_proto4);
 }
 
 static struct pernet_operations dccp_net_ops = {
@@ -972,11 +967,33 @@ static struct pernet_operations dccp_net_ops = {
 
 static int __init nf_conntrack_proto_dccp_init(void)
 {
-       return register_pernet_subsys(&dccp_net_ops);
+       int ret;
+
+       ret = nf_ct_l4proto_register(&dccp_proto4);
+       if (ret < 0)
+               goto out_dccp4;
+
+       ret = nf_ct_l4proto_register(&dccp_proto6);
+       if (ret < 0)
+               goto out_dccp6;
+
+       ret = register_pernet_subsys(&dccp_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
+       return 0;
+out_pernet:
+       nf_ct_l4proto_unregister(&dccp_proto6);
+out_dccp6:
+       nf_ct_l4proto_unregister(&dccp_proto4);
+out_dccp4:
+       return ret;
 }
 
 static void __exit nf_conntrack_proto_dccp_fini(void)
 {
+       nf_ct_l4proto_unregister(&dccp_proto6);
+       nf_ct_l4proto_unregister(&dccp_proto4);
        unregister_pernet_subsys(&dccp_net_ops);
 }
 
index b09b7af7f6f803414b962039e37d41df9fbb8a29..bd7d01d9c7e77d0e8a3a1e50116f854bb4925e14 100644 (file)
@@ -397,15 +397,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
 static int proto_gre_net_init(struct net *net)
 {
        int ret = 0;
-       ret = nf_conntrack_l4proto_register(net, &nf_conntrack_l4proto_gre4);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_gre4);
        if (ret < 0)
-               pr_err("nf_conntrack_l4proto_gre4 :protocol register failed.\n");
+               pr_err("nf_conntrack_gre4: pernet registration failed.\n");
        return ret;
 }
 
 static void proto_gre_net_exit(struct net *net)
 {
-       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_gre4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_gre4);
        nf_ct_gre_keymap_flush(net);
 }
 
@@ -418,11 +418,26 @@ static struct pernet_operations proto_gre_net_ops = {
 
 static int __init nf_ct_proto_gre_init(void)
 {
-       return register_pernet_subsys(&proto_gre_net_ops);
+       int ret;
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4);
+       if (ret < 0)
+               goto out_gre4;
+
+       ret = register_pernet_subsys(&proto_gre_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
+       return 0;
+out_pernet:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4);
+out_gre4:
+       return ret;
 }
 
 static void __exit nf_ct_proto_gre_fini(void)
 {
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4);
        unregister_pernet_subsys(&proto_gre_net_ops);
 }
 
index c746d61f83edb562f17b64ba63566bc0f12d8b2b..480f616d59361e0fff4abf182dc9f35974606187 100644 (file)
@@ -853,33 +853,28 @@ static int sctp_net_init(struct net *net)
 {
        int ret = 0;
 
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_sctp4);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_sctp4);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_sctp4 :protocol register failed.\n");
+               pr_err("nf_conntrack_sctp4: pernet registration failed.\n");
                goto out;
        }
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_sctp6);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_sctp6);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_sctp6 :protocol register failed.\n");
+               pr_err("nf_conntrack_sctp6: pernet registration failed.\n");
                goto cleanup_sctp4;
        }
        return 0;
 
 cleanup_sctp4:
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_sctp4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_sctp4);
 out:
        return ret;
 }
 
 static void sctp_net_exit(struct net *net)
 {
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_sctp6);
-       nf_conntrack_l4proto_unregister(net,
-                                       &nf_conntrack_l4proto_sctp4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_sctp6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_sctp4);
 }
 
 static struct pernet_operations sctp_net_ops = {
@@ -891,11 +886,33 @@ static struct pernet_operations sctp_net_ops = {
 
 static int __init nf_conntrack_proto_sctp_init(void)
 {
-       return register_pernet_subsys(&sctp_net_ops);
+       int ret;
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_sctp4);
+       if (ret < 0)
+               goto out_sctp4;
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_sctp6);
+       if (ret < 0)
+               goto out_sctp6;
+
+       ret = register_pernet_subsys(&sctp_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
+       return 0;
+out_pernet:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
+out_sctp6:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
+out_sctp4:
+       return ret;
 }
 
 static void __exit nf_conntrack_proto_sctp_fini(void)
 {
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
        unregister_pernet_subsys(&sctp_net_ops);
 }
 
index 4b66df2092869a16420573aa2ed64495746a067f..157489581c313b02456b18d0e3e886746a60671f 100644 (file)
@@ -336,30 +336,28 @@ static int udplite_net_init(struct net *net)
 {
        int ret = 0;
 
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_udplite4);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udplite4);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
+               pr_err("nf_conntrack_udplite4: pernet registration failed.\n");
                goto out;
        }
-       ret = nf_conntrack_l4proto_register(net,
-                                           &nf_conntrack_l4proto_udplite6);
+       ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udplite6);
        if (ret < 0) {
-               pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
+               pr_err("nf_conntrack_udplite6: pernet registration failed.\n");
                goto cleanup_udplite4;
        }
        return 0;
 
 cleanup_udplite4:
-       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite4);
 out:
        return ret;
 }
 
 static void udplite_net_exit(struct net *net)
 {
-       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite6);
-       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite6);
+       nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite4);
 }
 
 static struct pernet_operations udplite_net_ops = {
@@ -371,11 +369,33 @@ static struct pernet_operations udplite_net_ops = {
 
 static int __init nf_conntrack_proto_udplite_init(void)
 {
-       return register_pernet_subsys(&udplite_net_ops);
+       int ret;
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite4);
+       if (ret < 0)
+               goto out_udplite4;
+
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite6);
+       if (ret < 0)
+               goto out_udplite6;
+
+       ret = register_pernet_subsys(&udplite_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
+       return 0;
+out_pernet:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
+out_udplite6:
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
+out_udplite4:
+       return ret;
 }
 
 static void __exit nf_conntrack_proto_udplite_exit(void)
 {
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
+       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
        unregister_pernet_subsys(&udplite_net_ops);
 }
 
index df8f4f284481042800b3da96ab41bf3589ef512e..72a67bbe3518e954eb0435858d82690c4af7510d 100644 (file)
@@ -1440,8 +1440,25 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
 {
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
+       enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
        unsigned int matchoff, matchlen;
        unsigned int cseq, i;
+       union nf_inet_addr addr;
+       __be16 port;
+
+       /* Many Cisco IP phones use a high source port for SIP requests, but
+        * listen for the response on port 5060.  If we are the local
+        * router for one of these phones, save the port number from the
+        * Via: header so that nf_nat_sip can redirect the responses to
+        * the correct port.
+        */
+       if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
+                                   SIP_HDR_VIA_UDP, NULL, &matchoff,
+                                   &matchlen, &addr, &port) > 0 &&
+           port != ct->tuplehash[dir].tuple.src.u.udp.port &&
+           nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3))
+               ct_sip_info->forced_dport = port;
 
        for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
                const struct sip_handler *handler;
index 6e545e26289e5e82aca4a5de2744cce06cac54b9..87b95a2c270cd367fd0e910243221f60308c3263 100644 (file)
@@ -16,6 +16,7 @@
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
+#include <linux/netfilter/nf_conntrack_snmp.h>
 
 #define SNMP_PORT      161
 
index e7185c68481659445b571ab5e7866728dd3947ec..7936bf7f90bab46a160b31f4ae82e84aee88efc5 100644 (file)
@@ -472,13 +472,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
 {
        struct ctl_table *table;
 
-       if (net_eq(net, &init_net)) {
-               nf_ct_netfilter_header =
-                      register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
-               if (!nf_ct_netfilter_header)
-                       goto out;
-       }
-
        table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
                        GFP_KERNEL);
        if (!table)
@@ -502,10 +495,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
 out_unregister_netfilter:
        kfree(table);
 out_kmemdup:
-       if (net_eq(net, &init_net))
-               unregister_net_sysctl_table(nf_ct_netfilter_header);
-out:
-       printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n");
        return -ENOMEM;
 }
 
@@ -513,8 +502,6 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 {
        struct ctl_table *table;
 
-       if (net_eq(net, &init_net))
-               unregister_net_sysctl_table(nf_ct_netfilter_header);
        table = net->ct.sysctl_header->ctl_table_arg;
        unregister_net_sysctl_table(net->ct.sysctl_header);
        kfree(table);
@@ -530,51 +517,85 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 }
 #endif /* CONFIG_SYSCTL */
 
-static int nf_conntrack_net_init(struct net *net)
+static int nf_conntrack_pernet_init(struct net *net)
 {
        int ret;
 
-       ret = nf_conntrack_init(net);
+       ret = nf_conntrack_init_net(net);
        if (ret < 0)
                goto out_init;
+
        ret = nf_conntrack_standalone_init_proc(net);
        if (ret < 0)
                goto out_proc;
+
        net->ct.sysctl_checksum = 1;
        net->ct.sysctl_log_invalid = 0;
        ret = nf_conntrack_standalone_init_sysctl(net);
        if (ret < 0)
                goto out_sysctl;
+
        return 0;
 
 out_sysctl:
        nf_conntrack_standalone_fini_proc(net);
 out_proc:
-       nf_conntrack_cleanup(net);
+       nf_conntrack_cleanup_net(net);
 out_init:
        return ret;
 }
 
-static void nf_conntrack_net_exit(struct net *net)
+static void nf_conntrack_pernet_exit(struct net *net)
 {
        nf_conntrack_standalone_fini_sysctl(net);
        nf_conntrack_standalone_fini_proc(net);
-       nf_conntrack_cleanup(net);
+       nf_conntrack_cleanup_net(net);
 }
 
 static struct pernet_operations nf_conntrack_net_ops = {
-       .init = nf_conntrack_net_init,
-       .exit = nf_conntrack_net_exit,
+       .init = nf_conntrack_pernet_init,
+       .exit = nf_conntrack_pernet_exit,
 };
 
 static int __init nf_conntrack_standalone_init(void)
 {
-       return register_pernet_subsys(&nf_conntrack_net_ops);
+       int ret = nf_conntrack_init_start();
+       if (ret < 0)
+               goto out_start;
+
+#ifdef CONFIG_SYSCTL
+       nf_ct_netfilter_header =
+               register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
+       if (!nf_ct_netfilter_header) {
+               pr_err("nf_conntrack: can't register to sysctl.\n");
+               goto out_sysctl;
+       }
+#endif
+
+       ret = register_pernet_subsys(&nf_conntrack_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
+       nf_conntrack_init_end();
+       return 0;
+
+out_pernet:
+#ifdef CONFIG_SYSCTL
+       unregister_net_sysctl_table(nf_ct_netfilter_header);
+out_sysctl:
+#endif
+       nf_conntrack_cleanup_end();
+out_start:
+       return ret;
 }
 
 static void __exit nf_conntrack_standalone_fini(void)
 {
+       nf_conntrack_cleanup_start();
        unregister_pernet_subsys(&nf_conntrack_net_ops);
+#ifdef CONFIG_SYSCTL
+       unregister_net_sysctl_table(nf_ct_netfilter_header);
+#endif
        nf_conntrack_cleanup_end();
 }
 
index a878ce5b252c84e5508f432ace3e9ffe99f836d4..93da609d9d299375bdc704264fd021a317bd4e6b 100644 (file)
@@ -37,24 +37,15 @@ static struct nf_ct_ext_type timeout_extend __read_mostly = {
        .id     = NF_CT_EXT_TIMEOUT,
 };
 
-int nf_conntrack_timeout_init(struct net *net)
+int nf_conntrack_timeout_init(void)
 {
-       int ret = 0;
-
-       if (net_eq(net, &init_net)) {
-               ret = nf_ct_extend_register(&timeout_extend);
-               if (ret < 0) {
-                       printk(KERN_ERR "nf_ct_timeout: Unable to register "
-                                       "timeout extension.\n");
-                       return ret;
-               }
-       }
-
-       return 0;
+       int ret = nf_ct_extend_register(&timeout_extend);
+       if (ret < 0)
+               pr_err("nf_ct_timeout: Unable to register timeout extension.\n");
+       return ret;
 }
 
-void nf_conntrack_timeout_fini(struct net *net)
+void nf_conntrack_timeout_fini(void)
 {
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&timeout_extend);
+       nf_ct_extend_unregister(&timeout_extend);
 }
index 7ea8026f07c9c843698bb54c68eb236840956bf9..902fb0a6b38ad9baac15c3fc3f17a3e695510db8 100644 (file)
@@ -88,37 +88,28 @@ static void nf_conntrack_tstamp_fini_sysctl(struct net *net)
 }
 #endif
 
-int nf_conntrack_tstamp_init(struct net *net)
+int nf_conntrack_tstamp_pernet_init(struct net *net)
 {
-       int ret;
-
        net->ct.sysctl_tstamp = nf_ct_tstamp;
+       return nf_conntrack_tstamp_init_sysctl(net);
+}
 
-       if (net_eq(net, &init_net)) {
-               ret = nf_ct_extend_register(&tstamp_extend);
-               if (ret < 0) {
-                       printk(KERN_ERR "nf_ct_tstamp: Unable to register "
-                                       "extension\n");
-                       goto out_extend_register;
-               }
-       }
+void nf_conntrack_tstamp_pernet_fini(struct net *net)
+{
+       nf_conntrack_tstamp_fini_sysctl(net);
+       nf_ct_extend_unregister(&tstamp_extend);
+}
 
-       ret = nf_conntrack_tstamp_init_sysctl(net);
+int nf_conntrack_tstamp_init(void)
+{
+       int ret;
+       ret = nf_ct_extend_register(&tstamp_extend);
        if (ret < 0)
-               goto out_sysctl;
-
-       return 0;
-
-out_sysctl:
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&tstamp_extend);
-out_extend_register:
+               pr_err("nf_ct_tstamp: Unable to register extension\n");
        return ret;
 }
 
-void nf_conntrack_tstamp_fini(struct net *net)
+void nf_conntrack_tstamp_fini(void)
 {
-       nf_conntrack_tstamp_fini_sysctl(net);
-       if (net_eq(net, &init_net))
-               nf_ct_extend_unregister(&tstamp_extend);
+       nf_ct_extend_unregister(&tstamp_extend);
 }
index 16303c752213119fa9f2c19adddc73bf191d9d68..5951146e7688962f1281bff1a0f54c68bb0dde7f 100644 (file)
@@ -95,6 +95,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff,
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
        char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
        unsigned int buflen;
        union nf_inet_addr newaddr;
@@ -107,7 +108,8 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff,
        } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) &&
                   ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
                newaddr = ct->tuplehash[!dir].tuple.src.u3;
-               newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
+               newport = ct_sip_info->forced_dport ? :
+                         ct->tuplehash[!dir].tuple.src.u.udp.port;
        } else
                return 1;
 
@@ -144,6 +146,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
        unsigned int coff, matchoff, matchlen;
        enum sip_header_types hdr;
        union nf_inet_addr addr;
@@ -258,6 +261,21 @@ next:
            !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO))
                return NF_DROP;
 
+       /* Mangle destination port for Cisco phones, then fix up checksums */
+       if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
+               struct udphdr *uh;
+
+               if (!skb_make_writable(skb, skb->len))
+                       return NF_DROP;
+
+               uh = (void *)skb->data + protoff;
+               uh->dest = ct_sip_info->forced_dport;
+
+               if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
+                                             0, 0, NULL, 0))
+                       return NF_DROP;
+       }
+
        return NF_ACCEPT;
 }
 
@@ -311,8 +329,10 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
        union nf_inet_addr newaddr;
        u_int16_t port;
+       __be16 srcport;
        char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
        unsigned int buflen;
 
@@ -326,8 +346,9 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
        /* If the signalling port matches the connection's source port in the
         * original direction, try to use the destination port in the opposite
         * direction. */
-       if (exp->tuple.dst.u.udp.port ==
-           ct->tuplehash[dir].tuple.src.u.udp.port)
+       srcport = ct_sip_info->forced_dport ? :
+                 ct->tuplehash[dir].tuple.src.u.udp.port;
+       if (exp->tuple.dst.u.udp.port == srcport)
                port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
        else
                port = ntohs(exp->tuple.dst.u.udp.port);
diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c
new file mode 100644 (file)
index 0000000..12d4da8
--- /dev/null
@@ -0,0 +1,73 @@
+/* Xtables module to match packets using a BPF filter.
+ * Copyright 2013 Google Inc.
+ * Written by Willem de Bruijn <willemb@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/filter.h>
+
+#include <linux/netfilter/xt_bpf.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_AUTHOR("Willem de Bruijn <willemb@google.com>");
+MODULE_DESCRIPTION("Xtables: BPF filter match");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_bpf");
+MODULE_ALIAS("ip6t_bpf");
+
+static int bpf_mt_check(const struct xt_mtchk_param *par)
+{
+       struct xt_bpf_info *info = par->matchinfo;
+       struct sock_fprog program;
+
+       program.len = info->bpf_program_num_elem;
+       program.filter = (struct sock_filter __user *) info->bpf_program;
+       if (sk_unattached_filter_create(&info->filter, &program)) {
+               pr_info("bpf: check failed: parse error\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static bool bpf_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+       const struct xt_bpf_info *info = par->matchinfo;
+
+       return SK_RUN_FILTER(info->filter, skb);
+}
+
+static void bpf_mt_destroy(const struct xt_mtdtor_param *par)
+{
+       const struct xt_bpf_info *info = par->matchinfo;
+       sk_unattached_filter_destroy(info->filter);
+}
+
+static struct xt_match bpf_mt_reg __read_mostly = {
+       .name           = "bpf",
+       .revision       = 0,
+       .family         = NFPROTO_UNSPEC,
+       .checkentry     = bpf_mt_check,
+       .match          = bpf_mt,
+       .destroy        = bpf_mt_destroy,
+       .matchsize      = sizeof(struct xt_bpf_info),
+       .me             = THIS_MODULE,
+};
+
+static int __init bpf_mt_init(void)
+{
+       return xt_register_match(&bpf_mt_reg);
+}
+
+static void __exit bpf_mt_exit(void)
+{
+       xt_unregister_match(&bpf_mt_reg);
+}
+
+module_init(bpf_mt_init);
+module_exit(bpf_mt_exit);
diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c
new file mode 100644 (file)
index 0000000..9f8719d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * (C) 2013 Astaro GmbH & Co KG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_labels.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Xtables: add/match connection trackling labels");
+MODULE_ALIAS("ipt_connlabel");
+MODULE_ALIAS("ip6t_connlabel");
+
+static bool
+connlabel_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+       const struct xt_connlabel_mtinfo *info = par->matchinfo;
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct;
+       bool invert = info->options & XT_CONNLABEL_OP_INVERT;
+
+       ct = nf_ct_get(skb, &ctinfo);
+       if (ct == NULL || nf_ct_is_untracked(ct))
+               return invert;
+
+       if (info->options & XT_CONNLABEL_OP_SET)
+               return (nf_connlabel_set(ct, info->bit) == 0) ^ invert;
+
+       return nf_connlabel_match(ct, info->bit) ^ invert;
+}
+
+static int connlabel_mt_check(const struct xt_mtchk_param *par)
+{
+       const int options = XT_CONNLABEL_OP_INVERT |
+                           XT_CONNLABEL_OP_SET;
+       struct xt_connlabel_mtinfo *info = par->matchinfo;
+       int ret;
+       size_t words;
+
+       if (info->bit > XT_CONNLABEL_MAXBIT)
+               return -ERANGE;
+
+       if (info->options & ~options) {
+               pr_err("Unknown options in mask %x\n", info->options);
+               return -EINVAL;
+       }
+
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0) {
+               pr_info("cannot load conntrack support for proto=%u\n",
+                                                       par->family);
+               return ret;
+       }
+
+       par->net->ct.labels_used++;
+       words = BITS_TO_LONGS(info->bit+1);
+       if (words > par->net->ct.label_words)
+               par->net->ct.label_words = words;
+
+       return ret;
+}
+
+static void connlabel_mt_destroy(const struct xt_mtdtor_param *par)
+{
+       par->net->ct.labels_used--;
+       if (par->net->ct.labels_used == 0)
+               par->net->ct.label_words = 0;
+       nf_ct_l3proto_module_put(par->family);
+}
+
+static struct xt_match connlabels_mt_reg __read_mostly = {
+       .name           = "connlabel",
+       .family         = NFPROTO_UNSPEC,
+       .checkentry     = connlabel_mt_check,
+       .match          = connlabel_mt,
+       .matchsize      = sizeof(struct xt_connlabel_mtinfo),
+       .destroy        = connlabel_mt_destroy,
+       .me             = THIS_MODULE,
+};
+
+static int __init connlabel_mt_init(void)
+{
+       return xt_register_match(&connlabels_mt_reg);
+}
+
+static void __exit connlabel_mt_exit(void)
+{
+       xt_unregister_match(&connlabels_mt_reg);
+}
+
+module_init(connlabel_mt_init);
+module_exit(connlabel_mt_exit);
index c0353d55d56fc4221d72153c6f54849cb89f292b..74827e3b26a1b2da78e0029d250d2e20309ab895 100644 (file)
@@ -2185,7 +2185,6 @@ static struct pernet_operations __net_initdata netlink_net_ops = {
 
 static int __init netlink_proto_init(void)
 {
-       struct sk_buff *dummy_skb;
        int i;
        unsigned long limit;
        unsigned int order;
@@ -2194,7 +2193,7 @@ static int __init netlink_proto_init(void)
        if (err != 0)
                goto out;
 
-       BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb));
+       BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb));
 
        nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL);
        if (!nl_table)
index aa64ea441676a1ce9fc8c2417cc4487eaecf2cec..25522e56d3507645e6aa4d89bc692da91263dad9 100644 (file)
@@ -338,7 +338,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
                dev->active_target = target;
                dev->rf_mode = NFC_RF_INITIATOR;
 
-               if (dev->ops->check_presence)
+               if (dev->ops->check_presence && !dev->shutting_down)
                        mod_timer(&dev->check_pres_timer, jiffies +
                                  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
        }
@@ -429,7 +429,7 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
                rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
                                             cb_context);
 
-               if (!rc && dev->ops->check_presence)
+               if (!rc && dev->ops->check_presence && !dev->shutting_down)
                        mod_timer(&dev->check_pres_timer, jiffies +
                                  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
        } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
@@ -684,11 +684,6 @@ static void nfc_release(struct device *d)
 
        pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
-       if (dev->ops->check_presence) {
-               del_timer_sync(&dev->check_pres_timer);
-               cancel_work_sync(&dev->check_pres_work);
-       }
-
        nfc_genl_data_exit(&dev->genl_data);
        kfree(dev->targets);
        kfree(dev);
@@ -706,15 +701,16 @@ static void nfc_check_pres_work(struct work_struct *work)
                rc = dev->ops->check_presence(dev, dev->active_target);
                if (rc == -EOPNOTSUPP)
                        goto exit;
-               if (!rc) {
-                       mod_timer(&dev->check_pres_timer, jiffies +
-                                 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
-               } else {
+               if (rc) {
                        u32 active_target_idx = dev->active_target->idx;
                        device_unlock(&dev->dev);
                        nfc_target_lost(dev, active_target_idx);
                        return;
                }
+
+               if (!dev->shutting_down)
+                       mod_timer(&dev->check_pres_timer, jiffies +
+                                 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
        }
 
 exit:
@@ -761,6 +757,7 @@ struct nfc_dev *nfc_get_device(unsigned int idx)
  */
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
                                    u32 supported_protocols,
+                                   u32 supported_se,
                                    int tx_headroom, int tx_tailroom)
 {
        struct nfc_dev *dev;
@@ -778,6 +775,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 
        dev->ops = ops;
        dev->supported_protocols = supported_protocols;
+       dev->supported_se = supported_se;
+       dev->active_se = NFC_SE_NONE;
        dev->tx_headroom = tx_headroom;
        dev->tx_tailroom = tx_tailroom;
 
@@ -853,26 +852,27 @@ void nfc_unregister_device(struct nfc_dev *dev)
 
        id = dev->idx;
 
-       mutex_lock(&nfc_devlist_mutex);
-       nfc_devlist_generation++;
-
-       /* lock to avoid unregistering a device while an operation
-          is in progress */
-       device_lock(&dev->dev);
-       device_del(&dev->dev);
-       device_unlock(&dev->dev);
+       if (dev->ops->check_presence) {
+               device_lock(&dev->dev);
+               dev->shutting_down = true;
+               device_unlock(&dev->dev);
+               del_timer_sync(&dev->check_pres_timer);
+               cancel_work_sync(&dev->check_pres_work);
+       }
 
-       mutex_unlock(&nfc_devlist_mutex);
+       rc = nfc_genl_device_removed(dev);
+       if (rc)
+               pr_debug("The userspace won't be notified that the device %s "
+                        "was removed\n", dev_name(&dev->dev));
 
        nfc_llcp_unregister_device(dev);
 
-       rc = nfc_genl_device_removed(dev);
-       if (rc)
-               pr_debug("The userspace won't be notified that the device %s was removed\n",
-                        dev_name(&dev->dev));
+       mutex_lock(&nfc_devlist_mutex);
+       nfc_devlist_generation++;
+       device_del(&dev->dev);
+       mutex_unlock(&nfc_devlist_mutex);
 
        ida_simple_remove(&nfc_index_ida, id);
-
 }
 EXPORT_SYMBOL(nfc_unregister_device);
 
index 7d99410e6c1a542d91795a40f5e9d8bf9e719c5f..64f922be928127d8837899ae081044b48190447f 100644 (file)
@@ -280,14 +280,19 @@ static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
 static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
 {
        u8 param[2];
+       size_t param_len = 2;
 
        /* TODO: Find out what the identity reference data is
         * and fill param with it. HCI spec 6.1.3.5 */
 
        pr_debug("\n");
 
+       if (test_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &hdev->quirks))
+               param_len = 0;
+
        return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
-                                  NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
+                                  NFC_HCI_ADM_CLEAR_ALL_PIPE, param, param_len,
+                                  NULL);
 }
 
 int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
index 7bea574d59344f754ad74a1a390a8d742843549b..91020b210d8774416467bf009130cad9db5870a1 100644 (file)
@@ -57,6 +57,8 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
        int r = 0;
 
        mutex_lock(&hdev->msg_tx_mutex);
+       if (hdev->shutting_down)
+               goto exit;
 
        if (hdev->cmd_pending_msg) {
                if (timer_pending(&hdev->cmd_timer) == 0) {
@@ -295,6 +297,12 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
                goto exit;
        }
 
+       if (hdev->ops->event_received) {
+               r = hdev->ops->event_received(hdev, gate, event, skb);
+               if (r <= 0)
+                       goto exit_noskb;
+       }
+
        switch (event) {
        case NFC_HCI_EVT_TARGET_DISCOVERED:
                if (skb->len < 1) {     /* no status data? */
@@ -320,17 +328,15 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
                r = nfc_hci_target_discovered(hdev, gate);
                break;
        default:
-               if (hdev->ops->event_received) {
-                       hdev->ops->event_received(hdev, gate, event, skb);
-                       return;
-               }
-
+               pr_info("Discarded unknown event %x to gate %x\n", event, gate);
+               r = -EINVAL;
                break;
        }
 
 exit:
        kfree_skb(skb);
 
+exit_noskb:
        if (r) {
                /* TODO: There was an error dispatching the event,
                 * how to propagate up to nfc core?
@@ -669,8 +675,10 @@ static int hci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
 
        if (hdev->ops->tm_send)
                return hdev->ops->tm_send(hdev, skb);
-       else
-               return -ENOTSUPP;
+
+       kfree_skb(skb);
+
+       return -ENOTSUPP;
 }
 
 static int hci_check_presence(struct nfc_dev *nfc_dev,
@@ -787,7 +795,9 @@ static struct nfc_ops hci_nfc_ops = {
 
 struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
                                            struct nfc_hci_init_data *init_data,
+                                           unsigned long quirks,
                                            u32 protocols,
+                                           u32 supported_se,
                                            const char *llc_name,
                                            int tx_headroom,
                                            int tx_tailroom,
@@ -813,7 +823,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
                return NULL;
        }
 
-       hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols,
+       hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, supported_se,
                                         tx_headroom + HCI_CMDS_HEADROOM,
                                         tx_tailroom);
        if (!hdev->ndev) {
@@ -830,6 +840,8 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
 
        memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
 
+       hdev->quirks = quirks;
+
        return hdev;
 }
 EXPORT_SYMBOL(nfc_hci_allocate_device);
@@ -868,6 +880,28 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
 {
        struct hci_msg *msg, *n;
 
+       mutex_lock(&hdev->msg_tx_mutex);
+
+       if (hdev->cmd_pending_msg) {
+               if (hdev->cmd_pending_msg->cb)
+                       hdev->cmd_pending_msg->cb(
+                                            hdev->cmd_pending_msg->cb_context,
+                                            NULL, -ESHUTDOWN);
+               kfree(hdev->cmd_pending_msg);
+               hdev->cmd_pending_msg = NULL;
+       }
+
+       hdev->shutting_down = true;
+
+       mutex_unlock(&hdev->msg_tx_mutex);
+
+       del_timer_sync(&hdev->cmd_timer);
+       cancel_work_sync(&hdev->msg_tx_work);
+
+       cancel_work_sync(&hdev->msg_rx_work);
+
+       nfc_unregister_device(hdev->ndev);
+
        skb_queue_purge(&hdev->rx_hcp_frags);
        skb_queue_purge(&hdev->msg_rx_queue);
 
@@ -876,13 +910,6 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
                skb_queue_purge(&msg->msg_frags);
                kfree(msg);
        }
-
-       del_timer_sync(&hdev->cmd_timer);
-
-       nfc_unregister_device(hdev->ndev);
-
-       cancel_work_sync(&hdev->msg_tx_work);
-       cancel_work_sync(&hdev->msg_rx_work);
 }
 EXPORT_SYMBOL(nfc_hci_unregister_device);
 
index bc308a7ca6093f2857905beb3eecfe86d612671f..b6b4109f2343eb9cc9628c1c0ba07342d4f6c6f0 100644 (file)
@@ -105,6 +105,13 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
        }
 
        mutex_lock(&hdev->msg_tx_mutex);
+
+       if (hdev->shutting_down) {
+               err = -ESHUTDOWN;
+               mutex_unlock(&hdev->msg_tx_mutex);
+               goto out_skb_err;
+       }
+
        list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
        mutex_unlock(&hdev->msg_tx_mutex);
 
index df24be48d4dad2ee998bb483bdd4b1d109b24333..c6bc3bd950526ee2de42426337e74962e6181deb 100644 (file)
@@ -304,6 +304,8 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
 
        skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM);
 
+       __net_timestamp(skb);
+
        nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX);
 
        return nfc_data_exchange(dev, local->target_idx, skb,
index ec43914c92a9fbb416c5170e1d74440bb4dd1bf1..85bc75c38dea67544a39d7e352b144f3a8f4af0e 100644 (file)
@@ -54,7 +54,6 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
 
        skb_queue_purge(&sock->tx_queue);
        skb_queue_purge(&sock->tx_pending_queue);
-       skb_queue_purge(&sock->tx_backlog_queue);
 
        if (local == NULL)
                return;
@@ -668,6 +667,8 @@ static void nfc_llcp_tx_work(struct work_struct *work)
                        if (ptype == LLCP_PDU_I)
                                copy_skb = skb_copy(skb, GFP_ATOMIC);
 
+                       __net_timestamp(skb);
+
                        nfc_llcp_send_to_raw_sock(local, skb,
                                                  NFC_LLCP_DIRECTION_TX);
 
@@ -781,9 +782,15 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
 
        /* There is no sequence with UI frames */
        skb_pull(skb, LLCP_HEADER_SIZE);
-       if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
-               pr_err("receive queue is full\n");
-               skb_queue_head(&llcp_sock->tx_backlog_queue, skb);
+       if (!sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
+               /*
+                * UI frames will be freed from the socket layer, so we
+                * need to keep them alive until someone receives them.
+                */
+               skb_get(skb);
+       } else {
+               pr_err("Receive queue is full\n");
+               kfree_skb(skb);
        }
 
        nfc_llcp_sock_put(llcp_sock);
@@ -976,9 +983,15 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
                        pr_err("Received out of sequence I PDU\n");
 
                skb_pull(skb, LLCP_HEADER_SIZE + LLCP_SEQUENCE_SIZE);
-               if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
-                       pr_err("receive queue is full\n");
-                       skb_queue_head(&llcp_sock->tx_backlog_queue, skb);
+               if (!sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
+                       /*
+                        * I frames will be freed from the socket layer, so we
+                        * need to keep them alive until someone receives them.
+                        */
+                       skb_get(skb);
+               } else {
+                       pr_err("Receive queue is full\n");
+                       kfree_skb(skb);
                }
        }
 
@@ -1245,6 +1258,8 @@ static void nfc_llcp_rx_work(struct work_struct *work)
                print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
                               16, 1, skb->data, skb->len, true);
 
+       __net_timestamp(skb);
+
        nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
 
        switch (ptype) {
@@ -1296,6 +1311,13 @@ static void nfc_llcp_rx_work(struct work_struct *work)
        local->rx_pending = NULL;
 }
 
+static void __nfc_llcp_recv(struct nfc_llcp_local *local, struct sk_buff *skb)
+{
+       local->rx_pending = skb;
+       del_timer(&local->link_timer);
+       schedule_work(&local->rx_work);
+}
+
 void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
 {
        struct nfc_llcp_local *local = (struct nfc_llcp_local *) data;
@@ -1306,9 +1328,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
                return;
        }
 
-       local->rx_pending = skb_get(skb);
-       del_timer(&local->link_timer);
-       schedule_work(&local->rx_work);
+       __nfc_llcp_recv(local, skb);
 }
 
 int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
@@ -1319,9 +1339,7 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
        if (local == NULL)
                return -ENODEV;
 
-       local->rx_pending = skb_get(skb);
-       del_timer(&local->link_timer);
-       schedule_work(&local->rx_work);
+       __nfc_llcp_recv(local, skb);
 
        return 0;
 }
index 0d62366f8cc3f0e8fe33761d0ec6cc3e45bda677..0eae5c5095047dcd449af0ddba8fd402f79f50e2 100644 (file)
@@ -121,7 +121,6 @@ struct nfc_llcp_sock {
 
        struct sk_buff_head tx_queue;
        struct sk_buff_head tx_pending_queue;
-       struct sk_buff_head tx_backlog_queue;
 
        struct list_head accept_queue;
        struct sock *parent;
index fea22eb41b8242a1fb80d22c6aa2ca6515d78d0e..5332751943a9ec564befadda63a5a3749d7434c1 100644 (file)
@@ -672,25 +672,27 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        copied = min_t(unsigned int, rlen, len);
 
        cskb = skb;
-       if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) {
+       if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
                if (!(flags & MSG_PEEK))
                        skb_queue_head(&sk->sk_receive_queue, skb);
                return -EFAULT;
        }
 
+       sock_recv_timestamp(msg, sk, skb);
+
        if (sk->sk_type == SOCK_DGRAM && msg->msg_name) {
                struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb);
-               struct sockaddr_nfc_llcp sockaddr;
+               struct sockaddr_nfc_llcp *sockaddr =
+                       (struct sockaddr_nfc_llcp *) msg->msg_name;
 
-               pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap);
+               msg->msg_namelen = sizeof(struct sockaddr_nfc_llcp);
 
-               sockaddr.sa_family = AF_NFC;
-               sockaddr.nfc_protocol = NFC_PROTO_NFC_DEP;
-               sockaddr.dsap = ui_cb->dsap;
-               sockaddr.ssap = ui_cb->ssap;
+               pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap);
 
-               memcpy(msg->msg_name, &sockaddr, sizeof(sockaddr));
-               msg->msg_namelen = sizeof(sockaddr);
+               sockaddr->sa_family = AF_NFC;
+               sockaddr->nfc_protocol = NFC_PROTO_NFC_DEP;
+               sockaddr->dsap = ui_cb->dsap;
+               sockaddr->ssap = ui_cb->ssap;
        }
 
        /* Mark read part of skb as used */
@@ -806,7 +808,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
        llcp_sock->reserved_ssap = LLCP_SAP_MAX;
        skb_queue_head_init(&llcp_sock->tx_queue);
        skb_queue_head_init(&llcp_sock->tx_pending_queue);
-       skb_queue_head_init(&llcp_sock->tx_backlog_queue);
        INIT_LIST_HEAD(&llcp_sock->accept_queue);
 
        if (sock != NULL)
@@ -821,7 +822,6 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 
        skb_queue_purge(&sock->tx_queue);
        skb_queue_purge(&sock->tx_pending_queue);
-       skb_queue_purge(&sock->tx_backlog_queue);
 
        list_del_init(&sock->accept_queue);
 
index 5f98dc1bf03943abfd3315109acf94431858a9e2..48ada0ec749ec369bb6fc78308f12805cfa90c69 100644 (file)
@@ -658,6 +658,7 @@ static struct nfc_ops nci_nfc_ops = {
  */
 struct nci_dev *nci_allocate_device(struct nci_ops *ops,
                                    __u32 supported_protocols,
+                                   __u32 supported_se,
                                    int tx_headroom, int tx_tailroom)
 {
        struct nci_dev *ndev;
@@ -680,6 +681,7 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
 
        ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
                                            supported_protocols,
+                                           supported_se,
                                            tx_headroom + NCI_DATA_HDR_SIZE,
                                            tx_tailroom);
        if (!ndev->nfc_dev)
index 3568ae16786d513830040ddb020c33237649198b..504b883439f1b535b565c8efdc79e965afe465d4 100644 (file)
@@ -366,6 +366,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
        if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
            nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
            nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
+           nla_put_u32(msg, NFC_ATTR_SE, dev->supported_se) ||
            nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
            nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
                goto nla_put_failure;
index f996db343247aab3b155a27df330252de35761db..d8c13a965459cd60af3a799621ecb4686aefe93b 100644 (file)
@@ -1989,10 +1989,9 @@ static struct pernet_operations ovs_net_ops = {
 
 static int __init dp_init(void)
 {
-       struct sk_buff *dummy_skb;
        int err;
 
-       BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > sizeof(dummy_skb->cb));
+       BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
 
        pr_info("Open vSwitch switching datapath\n");
 
index 5d460c37df07ce70b615de1cff8e2191e358bab1..0531de6c7a4a858e6c5ef88c53e9dd639aff6fef 100644 (file)
@@ -69,7 +69,6 @@ static int internal_dev_mac_addr(struct net_device *dev, void *p)
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
-       dev->addr_assign_type &= ~NET_ADDR_RANDOM;
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
        return 0;
 }
@@ -98,7 +97,7 @@ static int internal_dev_stop(struct net_device *netdev)
 static void internal_dev_getinfo(struct net_device *netdev,
                                 struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "openvswitch");
+       strlcpy(info->driver, "openvswitch", sizeof(info->driver));
 }
 
 static const struct ethtool_ops internal_dev_ethtool_ops = {
index 05996d0dd828f57793441214831d88e0cf367b3e..5b0fd291babb9c1de343a0bfdd28b4054e392b4d 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/net.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
@@ -792,10 +793,9 @@ static const struct net_proto_family rxrpc_family_ops = {
  */
 static int __init af_rxrpc_init(void)
 {
-       struct sk_buff *dummy_skb;
        int ret = -1;
 
-       BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof(dummy_skb->cb));
+       BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > FIELD_SIZEOF(struct sk_buff, cb));
 
        rxrpc_epoch = htonl(get_seconds());
 
index 65d240cbf74b7513e7dc42effdc7f126bb4fff65..8579c4bb20c9daf093adf0b33b8bd13a94f5c6e0 100644 (file)
@@ -485,8 +485,9 @@ errout:
        return err;
 }
 
-struct tc_action *tcf_action_init_1(struct nlattr *nla, struct nlattr *est,
-                                   char *name, int ovr, int bind)
+struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
+                                   struct nlattr *est, char *name, int ovr,
+                                   int bind)
 {
        struct tc_action *a;
        struct tc_action_ops *a_o;
@@ -542,9 +543,9 @@ struct tc_action *tcf_action_init_1(struct nlattr *nla, struct nlattr *est,
 
        /* backward compatibility for policer */
        if (name == NULL)
-               err = a_o->init(tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
+               err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
        else
-               err = a_o->init(nla, est, a, ovr, bind);
+               err = a_o->init(net, nla, est, a, ovr, bind);
        if (err < 0)
                goto err_free;
 
@@ -566,8 +567,9 @@ err_out:
        return ERR_PTR(err);
 }
 
-struct tc_action *tcf_action_init(struct nlattr *nla, struct nlattr *est,
-                                 char *name, int ovr, int bind)
+struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
+                                 struct nlattr *est, char *name, int ovr,
+                                 int bind)
 {
        struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
        struct tc_action *head = NULL, *act, *act_prev = NULL;
@@ -579,7 +581,7 @@ struct tc_action *tcf_action_init(struct nlattr *nla, struct nlattr *est,
                return ERR_PTR(err);
 
        for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
-               act = tcf_action_init_1(tb[i], est, name, ovr, bind);
+               act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
                if (IS_ERR(act))
                        goto err;
                act->order = i;
@@ -960,7 +962,7 @@ tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
        struct tc_action *a;
        u32 seq = n->nlmsg_seq;
 
-       act = tcf_action_init(nla, NULL, NULL, ovr, 0);
+       act = tcf_action_init(net, nla, NULL, NULL, ovr, 0);
        if (act == NULL)
                goto done;
        if (IS_ERR(act)) {
index 2c8ad7c86e4340e246394e075e18fcffc26ca722..08fa1e8a4ca4a5a0d45e399103cd680622b870bd 100644 (file)
@@ -51,7 +51,7 @@ static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
        [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
 };
 
-static int tcf_csum_init(struct nlattr *nla, struct nlattr *est,
+static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
                         struct tc_action *a, int ovr, int bind)
 {
        struct nlattr *tb[TCA_CSUM_MAX + 1];
index 05d60859d8e3d1c2eb700ff7d1d63d81d9f98894..fd2b3cff5fa28cf4da25690da9e7bad410c60a78 100644 (file)
@@ -58,8 +58,9 @@ static const struct nla_policy gact_policy[TCA_GACT_MAX + 1] = {
        [TCA_GACT_PROB]         = { .len = sizeof(struct tc_gact_p) },
 };
 
-static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
-                        struct tc_action *a, int ovr, int bind)
+static int tcf_gact_init(struct net *net, struct nlattr *nla,
+                        struct nlattr *est, struct tc_action *a,
+                        int ovr, int bind)
 {
        struct nlattr *tb[TCA_GACT_MAX + 1];
        struct tc_gact *parm;
index 58fb3c7aab9eea8a0e65851948dd3d81da4fe3b8..0fb9e3f567e62340ee5b3d707d34591e54e7c7f2 100644 (file)
@@ -102,7 +102,7 @@ static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
        [TCA_IPT_TARG]  = { .len = sizeof(struct xt_entry_target) },
 };
 
-static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est,
+static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                        struct tc_action *a, int ovr, int bind)
 {
        struct nlattr *tb[TCA_IPT_MAX + 1];
index 9c0fd0c788145c0b6fa877463022f5ec90a707e2..5d676edc22a66010ee93eea8b4663a45f60b4c75 100644 (file)
@@ -62,8 +62,9 @@ static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
        [TCA_MIRRED_PARMS]      = { .len = sizeof(struct tc_mirred) },
 };
 
-static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
-                          struct tc_action *a, int ovr, int bind)
+static int tcf_mirred_init(struct net *net, struct nlattr *nla,
+                          struct nlattr *est, struct tc_action *a, int ovr,
+                          int bind)
 {
        struct nlattr *tb[TCA_MIRRED_MAX + 1];
        struct tc_mirred *parm;
@@ -88,7 +89,7 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
                return -EINVAL;
        }
        if (parm->ifindex) {
-               dev = __dev_get_by_index(&init_net, parm->ifindex);
+               dev = __dev_get_by_index(net, parm->ifindex);
                if (dev == NULL)
                        return -ENODEV;
                switch (dev->type) {
index b5d029eb44f23216cce377506b39e9bbf7997dc3..876f0ef29694a3f28260a221d0862d4fe3756f8d 100644 (file)
@@ -44,7 +44,7 @@ static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
        [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) },
 };
 
-static int tcf_nat_init(struct nlattr *nla, struct nlattr *est,
+static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                        struct tc_action *a, int ovr, int bind)
 {
        struct nlattr *tb[TCA_NAT_MAX + 1];
index 45c53ab067a63240357a970e15ab2633802211d6..0c3faddf3f2c75f1505f5c7c1862f24a4c769dfa 100644 (file)
@@ -38,8 +38,9 @@ static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = {
        [TCA_PEDIT_PARMS]       = { .len = sizeof(struct tc_pedit) },
 };
 
-static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est,
-                         struct tc_action *a, int ovr, int bind)
+static int tcf_pedit_init(struct net *net, struct nlattr *nla,
+                         struct nlattr *est, struct tc_action *a,
+                         int ovr, int bind)
 {
        struct nlattr *tb[TCA_PEDIT_MAX + 1];
        struct tc_pedit *parm;
index a9de23297d47759f3fa50113b1bf190f51bf4063..8dbd695c160bc7c1e55c3d07a41d150b963dc032 100644 (file)
@@ -130,8 +130,9 @@ static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = {
        [TCA_POLICE_RESULT]     = { .type = NLA_U32 },
 };
 
-static int tcf_act_police_locate(struct nlattr *nla, struct nlattr *est,
-                                struct tc_action *a, int ovr, int bind)
+static int tcf_act_police_locate(struct net *net, struct nlattr *nla,
+                                struct nlattr *est, struct tc_action *a,
+                                int ovr, int bind)
 {
        unsigned int h;
        int ret = 0, err;
index 3714f60f0b3c5869725e449de8456ec9bd6b20fe..7725eb4ab756caa841eca2e0f4778880c310e5c4 100644 (file)
@@ -95,8 +95,9 @@ static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = {
        [TCA_DEF_DATA]  = { .type = NLA_STRING, .len = SIMP_MAX_DATA },
 };
 
-static int tcf_simp_init(struct nlattr *nla, struct nlattr *est,
-                        struct tc_action *a, int ovr, int bind)
+static int tcf_simp_init(struct net *net, struct nlattr *nla,
+                        struct nlattr *est, struct tc_action *a,
+                        int ovr, int bind)
 {
        struct nlattr *tb[TCA_DEF_MAX + 1];
        struct tc_defact *parm;
index 476e0fac6712292a133d5645f98ca889af52a8c4..cb4221171f93f0c5b8fbb98f41b11241aa17d02a 100644 (file)
@@ -67,8 +67,9 @@ static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
        [TCA_SKBEDIT_MARK]              = { .len = sizeof(u32) },
 };
 
-static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est,
-                        struct tc_action *a, int ovr, int bind)
+static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
+                           struct nlattr *est, struct tc_action *a,
+                           int ovr, int bind)
 {
        struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
        struct tc_skbedit *parm;
index ff55ed6c49b24115f4dc78b505da368a34e06b6b..964f5e4f4b8ac641f3f96b1b5a69d3c64aa70d48 100644 (file)
@@ -321,7 +321,7 @@ replay:
                }
        }
 
-       err = tp->ops->change(skb, tp, cl, t->tcm_handle, tca, &fh);
+       err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh);
        if (err == 0) {
                if (tp_created) {
                        spin_lock_bh(root_lock);
@@ -508,7 +508,7 @@ void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
 }
 EXPORT_SYMBOL(tcf_exts_destroy);
 
-int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
+int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
                  struct nlattr *rate_tlv, struct tcf_exts *exts,
                  const struct tcf_ext_map *map)
 {
@@ -519,7 +519,7 @@ int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
                struct tc_action *act;
 
                if (map->police && tb[map->police]) {
-                       act = tcf_action_init_1(tb[map->police], rate_tlv,
+                       act = tcf_action_init_1(net, tb[map->police], rate_tlv,
                                                "police", TCA_ACT_NOREPLACE,
                                                TCA_ACT_BIND);
                        if (IS_ERR(act))
@@ -528,8 +528,9 @@ int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
                        act->type = TCA_OLD_COMPAT;
                        exts->action = act;
                } else if (map->action && tb[map->action]) {
-                       act = tcf_action_init(tb[map->action], rate_tlv, NULL,
-                                             TCA_ACT_NOREPLACE, TCA_ACT_BIND);
+                       act = tcf_action_init(net, tb[map->action], rate_tlv,
+                                             NULL, TCA_ACT_NOREPLACE,
+                                             TCA_ACT_BIND);
                        if (IS_ERR(act))
                                return PTR_ERR(act);
 
index 344a11b342e5ad333430ba68605bec6ce5f27f5c..d76a35d0dc85b82ddd9b8f2cc037b1ff0d31f5d5 100644 (file)
@@ -132,15 +132,16 @@ static const struct nla_policy basic_policy[TCA_BASIC_MAX + 1] = {
        [TCA_BASIC_EMATCHES]    = { .type = NLA_NESTED },
 };
 
-static int basic_set_parms(struct tcf_proto *tp, struct basic_filter *f,
-                          unsigned long base, struct nlattr **tb,
+static int basic_set_parms(struct net *net, struct tcf_proto *tp,
+                          struct basic_filter *f, unsigned long base,
+                          struct nlattr **tb,
                           struct nlattr *est)
 {
        int err = -EINVAL;
        struct tcf_exts e;
        struct tcf_ematch_tree t;
 
-       err = tcf_exts_validate(tp, tb, est, &e, &basic_ext_map);
+       err = tcf_exts_validate(net, tp, tb, est, &e, &basic_ext_map);
        if (err < 0)
                return err;
 
@@ -162,7 +163,7 @@ errout:
        return err;
 }
 
-static int basic_change(struct sk_buff *in_skb,
+static int basic_change(struct net *net, struct sk_buff *in_skb,
                        struct tcf_proto *tp, unsigned long base, u32 handle,
                        struct nlattr **tca, unsigned long *arg)
 {
@@ -182,7 +183,7 @@ static int basic_change(struct sk_buff *in_skb,
        if (f != NULL) {
                if (handle && f->handle != handle)
                        return -EINVAL;
-               return basic_set_parms(tp, f, base, tb, tca[TCA_RATE]);
+               return basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE]);
        }
 
        err = -ENOBUFS;
@@ -208,7 +209,7 @@ static int basic_change(struct sk_buff *in_skb,
                f->handle = head->hgenerator;
        }
 
-       err = basic_set_parms(tp, f, base, tb, tca[TCA_RATE]);
+       err = basic_set_parms(net, tp, f, base, tb, tca[TCA_RATE]);
        if (err < 0)
                goto errout;
 
index 6db7855b9029ee26dcd97d73c43862a93c35b6c4..3a294eb98d6178733edc49c98da4069ccf643a39 100644 (file)
@@ -178,7 +178,7 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = {
        [TCA_CGROUP_EMATCHES]   = { .type = NLA_NESTED },
 };
 
-static int cls_cgroup_change(struct sk_buff *in_skb,
+static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
                             struct tcf_proto *tp, unsigned long base,
                             u32 handle, struct nlattr **tca,
                             unsigned long *arg)
@@ -215,7 +215,8 @@ static int cls_cgroup_change(struct sk_buff *in_skb,
        if (err < 0)
                return err;
 
-       err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &cgroup_ext_map);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e,
+                               &cgroup_ext_map);
        if (err < 0)
                return err;
 
index ce82d0cb1b4762e8ffcc58d8e46beacd86e31db0..aa36a8c8b33bf27e286443f23ba27393e7156cda 100644 (file)
@@ -351,7 +351,7 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
        [TCA_FLOW_PERTURB]      = { .type = NLA_U32 },
 };
 
-static int flow_change(struct sk_buff *in_skb, 
+static int flow_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle, struct nlattr **tca,
                       unsigned long *arg)
@@ -397,7 +397,7 @@ static int flow_change(struct sk_buff *in_skb,
                        return -EOPNOTSUPP;
        }
 
-       err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
        if (err < 0)
                return err;
 
index 4075a0aef2aa2e83fdf167c056e216c3abfc6204..1135d8227f9bf1811a2c45c211b80e6b9a69706f 100644 (file)
@@ -192,7 +192,7 @@ static const struct nla_policy fw_policy[TCA_FW_MAX + 1] = {
 };
 
 static int
-fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,
+fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
        struct nlattr **tb, struct nlattr **tca, unsigned long base)
 {
        struct fw_head *head = (struct fw_head *)tp->root;
@@ -200,7 +200,7 @@ fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,
        u32 mask;
        int err;
 
-       err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &fw_ext_map);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, &fw_ext_map);
        if (err < 0)
                return err;
 
@@ -233,7 +233,7 @@ errout:
        return err;
 }
 
-static int fw_change(struct sk_buff *in_skb,
+static int fw_change(struct net *net, struct sk_buff *in_skb,
                     struct tcf_proto *tp, unsigned long base,
                     u32 handle,
                     struct nlattr **tca,
@@ -255,7 +255,7 @@ static int fw_change(struct sk_buff *in_skb,
        if (f != NULL) {
                if (f->id != handle && handle)
                        return -EINVAL;
-               return fw_change_attrs(tp, f, tb, tca, base);
+               return fw_change_attrs(net, tp, f, tb, tca, base);
        }
 
        if (!handle)
@@ -282,7 +282,7 @@ static int fw_change(struct sk_buff *in_skb,
 
        f->id = handle;
 
-       err = fw_change_attrs(tp, f, tb, tca, base);
+       err = fw_change_attrs(net, tp, f, tb, tca, base);
        if (err < 0)
                goto errout;
 
index c10d57bf98f2aa036434633db10a03fa530688da..37da567d833eff8368a3f881e2741e772f19c052 100644 (file)
@@ -335,9 +335,10 @@ static const struct nla_policy route4_policy[TCA_ROUTE4_MAX + 1] = {
        [TCA_ROUTE4_IIF]        = { .type = NLA_U32 },
 };
 
-static int route4_set_parms(struct tcf_proto *tp, unsigned long base,
-       struct route4_filter *f, u32 handle, struct route4_head *head,
-       struct nlattr **tb, struct nlattr *est, int new)
+static int route4_set_parms(struct net *net, struct tcf_proto *tp,
+                           unsigned long base, struct route4_filter *f,
+                           u32 handle, struct route4_head *head,
+                           struct nlattr **tb, struct nlattr *est, int new)
 {
        int err;
        u32 id = 0, to = 0, nhandle = 0x8000;
@@ -346,7 +347,7 @@ static int route4_set_parms(struct tcf_proto *tp, unsigned long base,
        struct route4_bucket *b;
        struct tcf_exts e;
 
-       err = tcf_exts_validate(tp, tb, est, &e, &route_ext_map);
+       err = tcf_exts_validate(net, tp, tb, est, &e, &route_ext_map);
        if (err < 0)
                return err;
 
@@ -427,7 +428,7 @@ errout:
        return err;
 }
 
-static int route4_change(struct sk_buff *in_skb,
+static int route4_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle,
                       struct nlattr **tca,
@@ -457,7 +458,7 @@ static int route4_change(struct sk_buff *in_skb,
                if (f->bkt)
                        old_handle = f->handle;
 
-               err = route4_set_parms(tp, base, f, handle, head, tb,
+               err = route4_set_parms(net, tp, base, f, handle, head, tb,
                        tca[TCA_RATE], 0);
                if (err < 0)
                        return err;
@@ -480,7 +481,7 @@ static int route4_change(struct sk_buff *in_skb,
        if (f == NULL)
                goto errout;
 
-       err = route4_set_parms(tp, base, f, handle, head, tb,
+       err = route4_set_parms(net, tp, base, f, handle, head, tb,
                tca[TCA_RATE], 1);
        if (err < 0)
                goto errout;
index 494bbb90924a36445d73ef5c921112b685722128..252d8b05872e511f029eab85d2e498ca4eb6d18a 100644 (file)
@@ -416,7 +416,7 @@ static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
        [TCA_RSVP_PINFO]        = { .len = sizeof(struct tc_rsvp_pinfo) },
 };
 
-static int rsvp_change(struct sk_buff *in_skb,
+static int rsvp_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle,
                       struct nlattr **tca,
@@ -440,7 +440,7 @@ static int rsvp_change(struct sk_buff *in_skb,
        if (err < 0)
                return err;
 
-       err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &rsvp_ext_map);
+       err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, &rsvp_ext_map);
        if (err < 0)
                return err;
 
index a1293b4ab7a13a38ae2653bc91bf48527cfdee7a..b86535a401695259ab9a765573180c33eb72fe00 100644 (file)
@@ -197,9 +197,10 @@ static const struct nla_policy tcindex_policy[TCA_TCINDEX_MAX + 1] = {
 };
 
 static int
-tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle,
-                 struct tcindex_data *p, struct tcindex_filter_result *r,
-                 struct nlattr **tb, struct nlattr *est)
+tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
+                 u32 handle, struct tcindex_data *p,
+                 struct tcindex_filter_result *r, struct nlattr **tb,
+                struct nlattr *est)
 {
        int err, balloc = 0;
        struct tcindex_filter_result new_filter_result, *old_r = r;
@@ -208,7 +209,7 @@ tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle,
        struct tcindex_filter *f = NULL; /* make gcc behave */
        struct tcf_exts e;
 
-       err = tcf_exts_validate(tp, tb, est, &e, &tcindex_ext_map);
+       err = tcf_exts_validate(net, tp, tb, est, &e, &tcindex_ext_map);
        if (err < 0)
                return err;
 
@@ -332,7 +333,7 @@ errout:
 }
 
 static int
-tcindex_change(struct sk_buff *in_skb,
+tcindex_change(struct net *net, struct sk_buff *in_skb,
               struct tcf_proto *tp, unsigned long base, u32 handle,
               struct nlattr **tca, unsigned long *arg)
 {
@@ -353,7 +354,8 @@ tcindex_change(struct sk_buff *in_skb,
        if (err < 0)
                return err;
 
-       return tcindex_set_parms(tp, base, handle, p, r, tb, tca[TCA_RATE]);
+       return tcindex_set_parms(net, tp, base, handle, p, r, tb,
+                                tca[TCA_RATE]);
 }
 
 
index c7c27bc91b5af300e74fe8434f7fcedb30635df6..eb07a1e536e6cb6f0b1f44099f130119490e9f52 100644 (file)
@@ -488,15 +488,15 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = {
        [TCA_U32_MARK]          = { .len = sizeof(struct tc_u32_mark) },
 };
 
-static int u32_set_parms(struct tcf_proto *tp, unsigned long base,
-                        struct tc_u_hnode *ht,
+static int u32_set_parms(struct net *net, struct tcf_proto *tp,
+                        unsigned long base, struct tc_u_hnode *ht,
                         struct tc_u_knode *n, struct nlattr **tb,
                         struct nlattr *est)
 {
        int err;
        struct tcf_exts e;
 
-       err = tcf_exts_validate(tp, tb, est, &e, &u32_ext_map);
+       err = tcf_exts_validate(net, tp, tb, est, &e, &u32_ext_map);
        if (err < 0)
                return err;
 
@@ -544,7 +544,7 @@ errout:
        return err;
 }
 
-static int u32_change(struct sk_buff *in_skb,
+static int u32_change(struct net *net, struct sk_buff *in_skb,
                      struct tcf_proto *tp, unsigned long base, u32 handle,
                      struct nlattr **tca,
                      unsigned long *arg)
@@ -570,7 +570,8 @@ static int u32_change(struct sk_buff *in_skb,
                if (TC_U32_KEY(n->handle) == 0)
                        return -EINVAL;
 
-               return u32_set_parms(tp, base, n->ht_up, n, tb, tca[TCA_RATE]);
+               return u32_set_parms(net, tp, base, n->ht_up, n, tb,
+                                    tca[TCA_RATE]);
        }
 
        if (tb[TCA_U32_DIVISOR]) {
@@ -656,7 +657,7 @@ static int u32_change(struct sk_buff *in_skb,
        }
 #endif
 
-       err = u32_set_parms(tp, base, ht, n, tb, tca[TCA_RATE]);
+       err = u32_set_parms(net, tp, base, ht, n, tb, tca[TCA_RATE]);
        if (err == 0) {
                struct tc_u_knode **ins;
                for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next)
index f898b1c58bd2cc9c35e49d796b2c4a06fe3376df..1c2e46cb919181f4005164ebe6e38cf5af5ecd6c 100644 (file)
@@ -595,7 +595,7 @@ static void sctp_v4_ecn_capable(struct sock *sk)
        INET_ECN_xmit(sk);
 }
 
-void sctp_addr_wq_timeout_handler(unsigned long arg)
+static void sctp_addr_wq_timeout_handler(unsigned long arg)
 {
        struct net *net = (struct net *)arg;
        struct sctp_sockaddr_entry *addrw, *temp;
index 5b5c876c80e9b543bd7b773c1a1f45f83f696e7b..0c612361c1534fa3edaaa0961873f2351371ee5e 100644 (file)
@@ -2426,9 +2426,8 @@ static struct pernet_operations unix_net_ops = {
 static int __init af_unix_init(void)
 {
        int rc = -1;
-       struct sk_buff *dummy_skb;
 
-       BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb));
+       BUILD_BUG_ON(sizeof(struct unix_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb));
 
        rc = proto_register(&unix_proto, 1);
        if (rc != 0) {
index 324e8d851dc4ca67fd0ded84a927e782c3647c8c..a4a14e8f55cc42f2c77146f73b4c55b8434337b5 100644 (file)
@@ -46,3 +46,65 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
 
        return err;
 }
+
+void cfg80211_ch_switch_notify(struct net_device *dev,
+                              struct cfg80211_chan_def *chandef)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       trace_cfg80211_ch_switch_notify(dev, chandef);
+
+       wdev_lock(wdev);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
+               goto out;
+
+       wdev->channel = chandef->chan;
+       nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
+out:
+       wdev_unlock(wdev);
+       return;
+}
+EXPORT_SYMBOL(cfg80211_ch_switch_notify);
+
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       bool ret;
+
+       trace_cfg80211_rx_spurious_frame(dev, addr);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
+               trace_cfg80211_return_bool(false);
+               return false;
+       }
+       ret = nl80211_unexpected_frame(dev, addr, gfp);
+       trace_cfg80211_return_bool(ret);
+       return ret;
+}
+EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
+
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       bool ret;
+
+       trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+                   wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
+               trace_cfg80211_return_bool(false);
+               return false;
+       }
+       ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
+       trace_cfg80211_return_bool(ret);
+       return ret;
+}
+EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
index a7990bb165295bcefbd88c6396026e2db8b7fa38..396373f3ec260b96a178dce7e72c239cf78bdc51 100644 (file)
@@ -76,6 +76,10 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
                        return false;
                if (!chandef->center_freq2)
                        return false;
+               /* adjacent is not allowed -- that's a 160 MHz channel */
+               if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
+                   chandef->center_freq2 - chandef->center_freq1 == 80)
+                       return false;
                break;
        case NL80211_CHAN_WIDTH_80:
                if (chandef->center_freq1 != control_freq + 30 &&
index b677eab55b68465494bffae68a2c38c2321f18ca..9245729694d277dd6beaeec4184d38b125dbc79b 100644 (file)
@@ -57,9 +57,6 @@ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
 {
        struct cfg80211_registered_device *result = NULL, *rdev;
 
-       if (!wiphy_idx_valid(wiphy_idx))
-               return NULL;
-
        assert_cfg80211_lock();
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
@@ -74,10 +71,8 @@ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
 
 int get_wiphy_idx(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *rdev;
-       if (!wiphy)
-               return WIPHY_IDX_STALE;
-       rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
        return rdev->wiphy_idx;
 }
 
@@ -86,9 +81,6 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
 {
        struct cfg80211_registered_device *rdev;
 
-       if (!wiphy_idx_valid(wiphy_idx))
-               return NULL;
-
        assert_cfg80211_lock();
 
        rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx);
@@ -309,7 +301,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 
        rdev->wiphy_idx = wiphy_counter++;
 
-       if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) {
+       if (unlikely(rdev->wiphy_idx < 0)) {
                wiphy_counter--;
                mutex_unlock(&cfg80211_mutex);
                /* ugh, wrapped! */
@@ -390,8 +382,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
 
                c = &wiphy->iface_combinations[i];
 
-               /* Combinations with just one interface aren't real */
-               if (WARN_ON(c->max_interfaces < 2))
+               /*
+                * Combinations with just one interface aren't real,
+                * however we make an exception for DFS.
+                */
+               if (WARN_ON((c->max_interfaces < 2) && !c->radar_detect_widths))
                        return -EINVAL;
 
                /* Need at least one channel */
@@ -406,6 +401,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
                                CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
                        return -EINVAL;
 
+               /* DFS only works on one channel. */
+               if (WARN_ON(c->radar_detect_widths &&
+                           (c->num_different_channels > 1)))
+                       return -EINVAL;
+
                if (WARN_ON(!c->n_limits))
                        return -EINVAL;
 
index 3563097169cb3ca8b767e9f5398a741c03a9885b..8396f7671c8db682c87baf657f607ae883e4128c 100644 (file)
@@ -18,6 +18,9 @@
 #include <net/cfg80211.h>
 #include "reg.h"
 
+
+#define WIPHY_IDX_INVALID      -1
+
 struct cfg80211_registered_device {
        const struct cfg80211_ops *ops;
        struct list_head list;
@@ -86,7 +89,7 @@ struct cfg80211_registered_device {
 
        /* must be last because of the way we do wiphy_priv(),
         * and it should at least be aligned to NETDEV_ALIGN */
-       struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
+       struct wiphy wiphy __aligned(NETDEV_ALIGN);
 };
 
 static inline
@@ -96,13 +99,6 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
        return container_of(wiphy, struct cfg80211_registered_device, wiphy);
 }
 
-/* Note 0 is valid, hence phy0 */
-static inline
-bool wiphy_idx_valid(int wiphy_idx)
-{
-       return wiphy_idx >= 0;
-}
-
 static inline void
 cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev)
 {
@@ -126,12 +122,6 @@ static inline void assert_cfg80211_lock(void)
        lockdep_assert_held(&cfg80211_mutex);
 }
 
-/*
- * You can use this to mark a wiphy_idx as not having an associated wiphy.
- * It guarantees cfg80211_rdev_by_wiphy_idx(wiphy_idx) will return NULL
- */
-#define WIPHY_IDX_STALE -1
-
 struct cfg80211_internal_bss {
        struct list_head list;
        struct rb_node rbn;
@@ -435,7 +425,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
                                 enum nl80211_iftype iftype,
                                 struct ieee80211_channel *chan,
-                                enum cfg80211_chan_mode chanmode);
+                                enum cfg80211_chan_mode chanmode,
+                                u8 radar_detect);
 
 static inline int
 cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
@@ -443,7 +434,7 @@ cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
                              enum nl80211_iftype iftype)
 {
        return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
-                                           CHAN_MODE_UNDEFINED);
+                                           CHAN_MODE_UNDEFINED, 0);
 }
 
 static inline int
@@ -460,7 +451,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
                      enum cfg80211_chan_mode chanmode)
 {
        return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-                                           chan, chanmode);
+                                           chan, chanmode, 0);
 }
 
 void
index 48c48ffafa1db51d9b96ea2d5a418e592dbcf436..e37862f1b1270d8e2056fb6289f01bf69b583720 100644 (file)
@@ -15,10 +15,10 @@ static void cfg80211_get_drvinfo(struct net_device *dev,
        strlcpy(info->version, init_utsname()->release, sizeof(info->version));
 
        if (wdev->wiphy->fw_version[0])
-               strncpy(info->fw_version, wdev->wiphy->fw_version,
+               strlcpy(info->fw_version, wdev->wiphy->fw_version,
                        sizeof(info->fw_version));
        else
-               strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
+               strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 
        strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
                sizeof(info->bus_info));
index f9d6ce5cfabbaebfc202f2d0290d8b1f0fbbc314..55957a284f6c7e82c9b403dae01798316224ad49 100644 (file)
 
 #define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50
 
+#define MESH_DEFAULT_BEACON_INTERVAL   1000    /* in 1024 us units (=TUs) */
+#define MESH_DEFAULT_DTIM_PERIOD       2
+#define MESH_DEFAULT_AWAKE_WINDOW      10      /* in 1024 us units (=TUs) */
+
 const struct mesh_config default_mesh_config = {
        .dot11MeshRetryTimeout = MESH_RET_T,
        .dot11MeshConfirmTimeout = MESH_CONF_T,
@@ -69,6 +73,8 @@ const struct mesh_config default_mesh_config = {
        .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT,
        .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL,
        .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
+       .power_mode = NL80211_MESH_POWER_ACTIVE,
+       .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW,
 };
 
 const struct mesh_setup default_mesh_setup = {
@@ -79,6 +85,8 @@ const struct mesh_setup default_mesh_setup = {
        .ie = NULL,
        .ie_len = 0,
        .is_secure = false,
+       .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL,
+       .dtim_period = MESH_DEFAULT_DTIM_PERIOD,
 };
 
 int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
index 5e8123ee63fd316d48e224fe65b8336300ec2b79..461e692cdfec40d07e99e873f596e347e5421670 100644 (file)
@@ -987,65 +987,3 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
        nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
-
-void cfg80211_ch_switch_notify(struct net_device *dev,
-                              struct cfg80211_chan_def *chandef)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_ch_switch_notify(dev, chandef);
-
-       wdev_lock(wdev);
-
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
-               goto out;
-
-       wdev->channel = chandef->chan;
-       nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
-out:
-       wdev_unlock(wdev);
-       return;
-}
-EXPORT_SYMBOL(cfg80211_ch_switch_notify);
-
-bool cfg80211_rx_spurious_frame(struct net_device *dev,
-                               const u8 *addr, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       bool ret;
-
-       trace_cfg80211_rx_spurious_frame(dev, addr);
-
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
-               trace_cfg80211_return_bool(false);
-               return false;
-       }
-       ret = nl80211_unexpected_frame(dev, addr, gfp);
-       trace_cfg80211_return_bool(ret);
-       return ret;
-}
-EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
-
-bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
-                                       const u8 *addr, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       bool ret;
-
-       trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
-
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
-                   wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
-               trace_cfg80211_return_bool(false);
-               return false;
-       }
-       ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
-       trace_cfg80211_return_bool(ret);
-       return ret;
-}
-EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
index f45706adaf3411813133704d41a12aa9d1d59712..33de80364c5cd183f344b8cc72f03810855141f3 100644 (file)
@@ -856,6 +856,9 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
                    nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
                                c->max_interfaces))
                        goto nla_put_failure;
+               if (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
+                               c->radar_detect_widths))
+                       goto nla_put_failure;
 
                nla_nest_end(msg, nl_combi);
        }
@@ -2079,6 +2082,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
            !(rdev->wiphy.interface_modes & (1 << type)))
                return -EOPNOTSUPP;
 
+       if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) {
+               nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
+                          ETH_ALEN);
+               if (!is_valid_ether_addr(params.macaddr))
+                       return -EADDRNOTAVAIL;
+       }
+
        if (info->attrs[NL80211_ATTR_4ADDR]) {
                params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
                err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
@@ -3001,6 +3011,18 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
            nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
                        sinfo->beacon_loss_count))
                goto nla_put_failure;
+       if ((sinfo->filled & STATION_INFO_LOCAL_PM) &&
+           nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM,
+                       sinfo->local_pm))
+               goto nla_put_failure;
+       if ((sinfo->filled & STATION_INFO_PEER_PM) &&
+           nla_put_u32(msg, NL80211_STA_INFO_PEER_PM,
+                       sinfo->peer_pm))
+               goto nla_put_failure;
+       if ((sinfo->filled & STATION_INFO_NONPEER_PM) &&
+           nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM,
+                       sinfo->nonpeer_pm))
+               goto nla_put_failure;
        if (sinfo->filled & STATION_INFO_BSS_PARAM) {
                bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
                if (!bss_param)
@@ -3188,13 +3210,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                        nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
        }
 
-       if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
-               params.listen_interval =
-                   nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
-
-       if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
-               params.ht_capa =
-                       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+       if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL] ||
+           info->attrs[NL80211_ATTR_HT_CAPABILITY])
+               return -EINVAL;
 
        if (!rdev->ops->change_station)
                return -EOPNOTSUPP;
@@ -3210,6 +3228,17 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                params.plink_state =
                    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
 
+       if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
+               enum nl80211_mesh_power_mode pm = nla_get_u32(
+                       info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
+
+               if (pm <= NL80211_MESH_POWER_UNKNOWN ||
+                   pm > NL80211_MESH_POWER_MAX)
+                       return -EINVAL;
+
+               params.local_pm = pm;
+       }
+
        switch (dev->ieee80211_ptr->iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
@@ -3217,6 +3246,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                /* disallow mesh-specific things */
                if (params.plink_action)
                        return -EINVAL;
+               if (params.local_pm)
+                       return -EINVAL;
 
                /* TDLS can't be set, ... */
                if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
@@ -3231,11 +3262,25 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                /* accept only the listed bits */
                if (params.sta_flags_mask &
                                ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                 BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                 BIT(NL80211_STA_FLAG_ASSOCIATED) |
                                  BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
                                  BIT(NL80211_STA_FLAG_WME) |
                                  BIT(NL80211_STA_FLAG_MFP)))
                        return -EINVAL;
 
+               /* but authenticated/associated only if driver handles it */
+               if (!(rdev->wiphy.features &
+                               NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
+                   params.sta_flags_mask &
+                               (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                BIT(NL80211_STA_FLAG_ASSOCIATED)))
+                       return -EINVAL;
+
+               /* reject other things that can't change */
+               if (params.supported_rates)
+                       return -EINVAL;
+
                /* must be last in here for error handling */
                params.vlan = get_vlan(info, rdev);
                if (IS_ERR(params.vlan))
@@ -3255,9 +3300,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                /* disallow things sta doesn't support */
                if (params.plink_action)
                        return -EINVAL;
-               if (params.ht_capa)
-                       return -EINVAL;
-               if (params.listen_interval >= 0)
+               if (params.local_pm)
                        return -EINVAL;
                /* reject any changes other than AUTHORIZED */
                if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
@@ -3267,9 +3310,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                /* disallow things mesh doesn't support */
                if (params.vlan)
                        return -EINVAL;
-               if (params.ht_capa)
-                       return -EINVAL;
-               if (params.listen_interval >= 0)
+               if (params.supported_rates)
                        return -EINVAL;
                /*
                 * No special handling for TDLS here -- the userspace
@@ -3393,17 +3434,31 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                /* but don't bother the driver with it */
                params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
 
+               /* allow authenticated/associated only if driver handles it */
+               if (!(rdev->wiphy.features &
+                               NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
+                   params.sta_flags_mask &
+                               (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                BIT(NL80211_STA_FLAG_ASSOCIATED)))
+                       return -EINVAL;
+
                /* must be last in here for error handling */
                params.vlan = get_vlan(info, rdev);
                if (IS_ERR(params.vlan))
                        return PTR_ERR(params.vlan);
                break;
        case NL80211_IFTYPE_MESH_POINT:
+               /* associated is disallowed */
+               if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
+                       return -EINVAL;
                /* TDLS peers cannot be added */
                if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
                        return -EINVAL;
                break;
        case NL80211_IFTYPE_STATION:
+               /* associated is disallowed */
+               if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
+                       return -EINVAL;
                /* Only TDLS peers can be added */
                if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
                        return -EINVAL;
@@ -3787,12 +3842,8 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
         * window between nl80211_init() and regulatory_init(), if that is
         * even possible.
         */
-       mutex_lock(&cfg80211_mutex);
-       if (unlikely(!cfg80211_regdomain)) {
-               mutex_unlock(&cfg80211_mutex);
+       if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
                return -EINPROGRESS;
-       }
-       mutex_unlock(&cfg80211_mutex);
 
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
                return -EINVAL;
@@ -3908,7 +3959,11 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
            nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
                        cur_params.dot11MeshHWMProotInterval) ||
            nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
-                       cur_params.dot11MeshHWMPconfirmationInterval))
+                       cur_params.dot11MeshHWMPconfirmationInterval) ||
+           nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
+                       cur_params.power_mode) ||
+           nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
+                       cur_params.dot11MeshAwakeWindowDuration))
                goto nla_put_failure;
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
@@ -3947,6 +4002,8 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
        [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
        [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
+       [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
+       [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
 };
 
 static const struct nla_policy
@@ -3967,13 +4024,15 @@ static int nl80211_parse_mesh_config(struct genl_info *info,
        struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
        u32 mask = 0;
 
-#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
-do {\
-       if (table[attr_num]) {\
-               cfg->param = nla_fn(table[attr_num]); \
-               mask |= (1 << (attr_num - 1)); \
-       } \
-} while (0);\
+#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
+do {                                                                       \
+       if (tb[attr]) {                                                     \
+               if (fn(tb[attr]) < min || fn(tb[attr]) > max)               \
+                       return -EINVAL;                                     \
+               cfg->param = fn(tb[attr]);                                  \
+               mask |= (1 << (attr - 1));                                  \
+       }                                                                   \
+} while (0)
 
 
        if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
@@ -3988,83 +4047,98 @@ do {\
        BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
 
        /* Fill in the params struct */
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
                                  mask, NL80211_MESHCONF_RETRY_TIMEOUT,
                                  nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
                                  mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
                                  nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
                                  mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
                                  nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
                                  mask, NL80211_MESHCONF_MAX_PEER_LINKS,
                                  nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
                                  mask, NL80211_MESHCONF_MAX_RETRIES,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
                                  mask, NL80211_MESHCONF_TTL, nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
                                  mask, NL80211_MESHCONF_ELEMENT_TTL,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
                                  mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
+                                 1, 255, mask,
                                  NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
                                  nla_get_u32);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
                                  mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
                                  mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
                                  nla_get_u32);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
                                  mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
                                  nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
+                                 1, 65535, mask,
                                  NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
                                  nla_get_u32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
-                                 mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+                                 1, 65535, mask,
+                                 NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
                                  nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
-                                 mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+                                 1, 65535, mask,
+                                 NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
                                  nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-                                 dot11MeshHWMPnetDiameterTraversalTime, mask,
+                                 dot11MeshHWMPnetDiameterTraversalTime,
+                                 1, 65535, mask,
                                  NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
                                  nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
-                                 NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
-                                 NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
+                                 mask, NL80211_MESHCONF_HWMP_ROOTMODE,
+                                 nla_get_u8);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
+                                 mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
                                  nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-                                 dot11MeshGateAnnouncementProtocol, mask,
-                                 NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+                                 dot11MeshGateAnnouncementProtocol, 0, 1,
+                                 mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
                                  mask, NL80211_MESHCONF_FORWARDING,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, 1, 255,
                                  mask, NL80211_MESHCONF_RSSI_THRESHOLD,
                                  nla_get_u32);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
                                  mask, NL80211_MESHCONF_HT_OPMODE,
                                  nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
-                                 mask,
+                                 1, 65535, mask,
                                  NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
                                  nla_get_u32);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
                                  mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
                                  nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-                                 dot11MeshHWMPconfirmationInterval, mask,
+                                 dot11MeshHWMPconfirmationInterval,
+                                 1, 65535, mask,
                                  NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
                                  nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
+                                 NL80211_MESH_POWER_ACTIVE,
+                                 NL80211_MESH_POWER_MAX,
+                                 mask, NL80211_MESHCONF_POWER_MODE,
+                                 nla_get_u32);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
+                                 0, 65535, mask,
+                                 NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
        if (mask_out)
                *mask_out = mask;
 
@@ -4152,6 +4226,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb,
 
 static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
 {
+       const struct ieee80211_regdomain *regdom;
        struct sk_buff *msg;
        void *hdr = NULL;
        struct nlattr *nl_reg_rules;
@@ -4174,35 +4249,36 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
        if (!hdr)
                goto put_failure;
 
-       if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
-                          cfg80211_regdomain->alpha2) ||
-           (cfg80211_regdomain->dfs_region &&
-            nla_put_u8(msg, NL80211_ATTR_DFS_REGION,
-                       cfg80211_regdomain->dfs_region)))
-               goto nla_put_failure;
-
        if (reg_last_request_cell_base() &&
            nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
                        NL80211_USER_REG_HINT_CELL_BASE))
                goto nla_put_failure;
 
+       rcu_read_lock();
+       regdom = rcu_dereference(cfg80211_regdomain);
+
+       if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
+           (regdom->dfs_region &&
+            nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
+               goto nla_put_failure_rcu;
+
        nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
        if (!nl_reg_rules)
-               goto nla_put_failure;
+               goto nla_put_failure_rcu;
 
-       for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
+       for (i = 0; i < regdom->n_reg_rules; i++) {
                struct nlattr *nl_reg_rule;
                const struct ieee80211_reg_rule *reg_rule;
                const struct ieee80211_freq_range *freq_range;
                const struct ieee80211_power_rule *power_rule;
 
-               reg_rule = &cfg80211_regdomain->reg_rules[i];
+               reg_rule = &regdom->reg_rules[i];
                freq_range = &reg_rule->freq_range;
                power_rule = &reg_rule->power_rule;
 
                nl_reg_rule = nla_nest_start(msg, i);
                if (!nl_reg_rule)
-                       goto nla_put_failure;
+                       goto nla_put_failure_rcu;
 
                if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
                                reg_rule->flags) ||
@@ -4216,10 +4292,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
                                power_rule->max_antenna_gain) ||
                    nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
                                power_rule->max_eirp))
-                       goto nla_put_failure;
+                       goto nla_put_failure_rcu;
 
                nla_nest_end(msg, nl_reg_rule);
        }
+       rcu_read_unlock();
 
        nla_nest_end(msg, nl_reg_rules);
 
@@ -4227,6 +4304,8 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
        err = genlmsg_reply(msg, info);
        goto out;
 
+nla_put_failure_rcu:
+       rcu_read_unlock();
 nla_put_failure:
        genlmsg_cancel(msg, hdr);
 put_failure:
@@ -4259,27 +4338,18 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
                dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
 
        nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
-                       rem_reg_rules) {
+                           rem_reg_rules) {
                num_rules++;
                if (num_rules > NL80211_MAX_SUPP_REG_RULES)
                        return -EINVAL;
        }
 
-       mutex_lock(&cfg80211_mutex);
-
-       if (!reg_is_valid_request(alpha2)) {
-               r = -EINVAL;
-               goto bad_reg;
-       }
-
        size_of_regd = sizeof(struct ieee80211_regdomain) +
-               (num_rules * sizeof(struct ieee80211_reg_rule));
+                      num_rules * sizeof(struct ieee80211_reg_rule);
 
        rd = kzalloc(size_of_regd, GFP_KERNEL);
-       if (!rd) {
-               r = -ENOMEM;
-               goto bad_reg;
-       }
+       if (!rd)
+               return -ENOMEM;
 
        rd->n_reg_rules = num_rules;
        rd->alpha2[0] = alpha2[0];
@@ -4293,10 +4363,10 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
                rd->dfs_region = dfs_region;
 
        nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
-                       rem_reg_rules) {
+                           rem_reg_rules) {
                nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
-                       nla_data(nl_reg_rule), nla_len(nl_reg_rule),
-                       reg_rule_policy);
+                         nla_data(nl_reg_rule), nla_len(nl_reg_rule),
+                         reg_rule_policy);
                r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
                if (r)
                        goto bad_reg;
@@ -4309,16 +4379,14 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       BUG_ON(rule_idx != num_rules);
+       mutex_lock(&cfg80211_mutex);
 
        r = set_regdom(rd);
-
+       /* set_regdom took ownership */
+       rd = NULL;
        mutex_unlock(&cfg80211_mutex);
 
-       return r;
-
  bad_reg:
-       mutex_unlock(&cfg80211_mutex);
        kfree(rd);
        return r;
 }
@@ -5867,6 +5935,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
+       if (info->attrs[NL80211_ATTR_USE_MFP]) {
+               connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
+               if (connect.mfp != NL80211_MFP_REQUIRED &&
+                   connect.mfp != NL80211_MFP_NO)
+                       return -EINVAL;
+       } else {
+               connect.mfp = NL80211_MFP_NO;
+       }
+
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
                connect.channel =
                        ieee80211_get_channel(wiphy,
@@ -6652,6 +6729,21 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
                            nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
                        return -EINVAL;
 
+       if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+               setup.beacon_interval =
+                       nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+               if (setup.beacon_interval < 10 ||
+                   setup.beacon_interval > 10000)
+                       return -EINVAL;
+       }
+
+       if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
+               setup.dtim_period =
+                       nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+               if (setup.dtim_period < 1 || setup.dtim_period > 100)
+                       return -EINVAL;
+       }
+
        if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
                /* parse additional setup parameters if given */
                err = nl80211_parse_mesh_setup(info, &setup);
@@ -8051,7 +8143,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
                        goto nla_put_failure;
        }
 
-       if (wiphy_idx_valid(request->wiphy_idx) &&
+       if (request->wiphy_idx != WIPHY_IDX_INVALID &&
            nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
                goto nla_put_failure;
 
index 82c4fc7c994cbe3a0dc89b4a6708f873fcc783d9..de02d633c212eb6ea516a7d87e05978a2a1b3ba9 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/list.h>
-#include <linux/random.h>
 #include <linux/ctype.h>
 #include <linux/nl80211.h>
 #include <linux/platform_device.h>
 #define REG_DBG_PRINT(args...)
 #endif
 
+enum reg_request_treatment {
+       REG_REQ_OK,
+       REG_REQ_IGNORE,
+       REG_REQ_INTERSECT,
+       REG_REQ_ALREADY_SET,
+};
+
 static struct regulatory_request core_request_world = {
        .initiator = NL80211_REGDOM_SET_BY_CORE,
        .alpha2[0] = '0',
@@ -76,7 +82,8 @@ static struct regulatory_request core_request_world = {
 };
 
 /* Receipt of information from last regulatory request */
-static struct regulatory_request *last_request = &core_request_world;
+static struct regulatory_request __rcu *last_request =
+       (void __rcu *)&core_request_world;
 
 /* To trigger userspace events */
 static struct platform_device *reg_pdev;
@@ -88,16 +95,16 @@ static struct device_type reg_device_type = {
 /*
  * Central wireless core regulatory domains, we only need two,
  * the current one and a world regulatory domain in case we have no
- * information to give us an alpha2
+ * information to give us an alpha2.
  */
-const struct ieee80211_regdomain *cfg80211_regdomain;
+const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
 
 /*
  * Protects static reg.c components:
- *     - cfg80211_world_regdom
- *     - cfg80211_regdom
- *     - last_request
- *     - reg_num_devs_support_basehint
+ *     - cfg80211_regdomain (if not used with RCU)
+ *     - cfg80211_world_regdom
+ *     - last_request (if not used with RCU)
+ *     - reg_num_devs_support_basehint
  */
 static DEFINE_MUTEX(reg_mutex);
 
@@ -112,6 +119,31 @@ static inline void assert_reg_lock(void)
        lockdep_assert_held(&reg_mutex);
 }
 
+static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
+{
+       return rcu_dereference_protected(cfg80211_regdomain,
+                                        lockdep_is_held(&reg_mutex));
+}
+
+static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
+{
+       return rcu_dereference_protected(wiphy->regd,
+                                        lockdep_is_held(&reg_mutex));
+}
+
+static void rcu_free_regdom(const struct ieee80211_regdomain *r)
+{
+       if (!r)
+               return;
+       kfree_rcu((struct ieee80211_regdomain *)r, rcu_head);
+}
+
+static struct regulatory_request *get_last_request(void)
+{
+       return rcu_dereference_check(last_request,
+                                    lockdep_is_held(&reg_mutex));
+}
+
 /* Used to queue up regulatory hints */
 static LIST_HEAD(reg_requests_list);
 static spinlock_t reg_requests_lock;
@@ -177,28 +209,37 @@ static char user_alpha2[2];
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-static void reset_regdomains(bool full_reset)
+static void reset_regdomains(bool full_reset,
+                            const struct ieee80211_regdomain *new_regdom)
 {
+       const struct ieee80211_regdomain *r;
+       struct regulatory_request *lr;
+
+       assert_reg_lock();
+
+       r = get_cfg80211_regdom();
+
        /* avoid freeing static information or freeing something twice */
-       if (cfg80211_regdomain == cfg80211_world_regdom)
-               cfg80211_regdomain = NULL;
+       if (r == cfg80211_world_regdom)
+               r = NULL;
        if (cfg80211_world_regdom == &world_regdom)
                cfg80211_world_regdom = NULL;
-       if (cfg80211_regdomain == &world_regdom)
-               cfg80211_regdomain = NULL;
+       if (r == &world_regdom)
+               r = NULL;
 
-       kfree(cfg80211_regdomain);
-       kfree(cfg80211_world_regdom);
+       rcu_free_regdom(r);
+       rcu_free_regdom(cfg80211_world_regdom);
 
        cfg80211_world_regdom = &world_regdom;
-       cfg80211_regdomain = NULL;
+       rcu_assign_pointer(cfg80211_regdomain, new_regdom);
 
        if (!full_reset)
                return;
 
-       if (last_request != &core_request_world)
-               kfree(last_request);
-       last_request = &core_request_world;
+       lr = get_last_request();
+       if (lr != &core_request_world && lr)
+               kfree_rcu(lr, rcu_head);
+       rcu_assign_pointer(last_request, &core_request_world);
 }
 
 /*
@@ -207,30 +248,29 @@ static void reset_regdomains(bool full_reset)
  */
 static void update_world_regdomain(const struct ieee80211_regdomain *rd)
 {
-       BUG_ON(!last_request);
+       struct regulatory_request *lr;
+
+       lr = get_last_request();
+
+       WARN_ON(!lr);
 
-       reset_regdomains(false);
+       reset_regdomains(false, rd);
 
        cfg80211_world_regdom = rd;
-       cfg80211_regdomain = rd;
 }
 
 bool is_world_regdom(const char *alpha2)
 {
        if (!alpha2)
                return false;
-       if (alpha2[0] == '0' && alpha2[1] == '0')
-               return true;
-       return false;
+       return alpha2[0] == '0' && alpha2[1] == '0';
 }
 
 static bool is_alpha2_set(const char *alpha2)
 {
        if (!alpha2)
                return false;
-       if (alpha2[0] != 0 && alpha2[1] != 0)
-               return true;
-       return false;
+       return alpha2[0] && alpha2[1];
 }
 
 static bool is_unknown_alpha2(const char *alpha2)
@@ -241,9 +281,7 @@ static bool is_unknown_alpha2(const char *alpha2)
         * Special case where regulatory domain was built by driver
         * but a specific alpha2 cannot be determined
         */
-       if (alpha2[0] == '9' && alpha2[1] == '9')
-               return true;
-       return false;
+       return alpha2[0] == '9' && alpha2[1] == '9';
 }
 
 static bool is_intersected_alpha2(const char *alpha2)
@@ -255,39 +293,30 @@ static bool is_intersected_alpha2(const char *alpha2)
         * result of an intersection between two regulatory domain
         * structures
         */
-       if (alpha2[0] == '9' && alpha2[1] == '8')
-               return true;
-       return false;
+       return alpha2[0] == '9' && alpha2[1] == '8';
 }
 
 static bool is_an_alpha2(const char *alpha2)
 {
        if (!alpha2)
                return false;
-       if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
-               return true;
-       return false;
+       return isalpha(alpha2[0]) && isalpha(alpha2[1]);
 }
 
 static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y)
 {
        if (!alpha2_x || !alpha2_y)
                return false;
-       if (alpha2_x[0] == alpha2_y[0] &&
-               alpha2_x[1] == alpha2_y[1])
-               return true;
-       return false;
+       return alpha2_x[0] == alpha2_y[0] && alpha2_x[1] == alpha2_y[1];
 }
 
 static bool regdom_changes(const char *alpha2)
 {
-       assert_cfg80211_lock();
+       const struct ieee80211_regdomain *r = get_cfg80211_regdom();
 
-       if (!cfg80211_regdomain)
+       if (!r)
                return true;
-       if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
-               return false;
-       return true;
+       return !alpha2_equal(r->alpha2, alpha2);
 }
 
 /*
@@ -301,38 +330,36 @@ static bool is_user_regdom_saved(void)
                return false;
 
        /* This would indicate a mistake on the design */
-       if (WARN((!is_world_regdom(user_alpha2) &&
-                 !is_an_alpha2(user_alpha2)),
+       if (WARN(!is_world_regdom(user_alpha2) && !is_an_alpha2(user_alpha2),
                 "Unexpected user alpha2: %c%c\n",
-                user_alpha2[0],
-                user_alpha2[1]))
+                user_alpha2[0], user_alpha2[1]))
                return false;
 
        return true;
 }
 
-static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
-                        const struct ieee80211_regdomain *src_regd)
+static const struct ieee80211_regdomain *
+reg_copy_regd(const struct ieee80211_regdomain *src_regd)
 {
        struct ieee80211_regdomain *regd;
-       int size_of_regd = 0;
+       int size_of_regd;
        unsigned int i;
 
-       size_of_regd = sizeof(struct ieee80211_regdomain) +
-         ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
+       size_of_regd =
+               sizeof(struct ieee80211_regdomain) +
+               src_regd->n_reg_rules * sizeof(struct ieee80211_reg_rule);
 
        regd = kzalloc(size_of_regd, GFP_KERNEL);
        if (!regd)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
 
        for (i = 0; i < src_regd->n_reg_rules; i++)
                memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
-                       sizeof(struct ieee80211_reg_rule));
+                      sizeof(struct ieee80211_reg_rule));
 
-       *dst_regd = regd;
-       return 0;
+       return regd;
 }
 
 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
@@ -347,9 +374,8 @@ static DEFINE_MUTEX(reg_regdb_search_mutex);
 static void reg_regdb_search(struct work_struct *work)
 {
        struct reg_regdb_search_request *request;
-       const struct ieee80211_regdomain *curdom, *regdom;
-       int i, r;
-       bool set_reg = false;
+       const struct ieee80211_regdomain *curdom, *regdom = NULL;
+       int i;
 
        mutex_lock(&cfg80211_mutex);
 
@@ -360,14 +386,11 @@ static void reg_regdb_search(struct work_struct *work)
                                           list);
                list_del(&request->list);
 
-               for (i=0; i<reg_regdb_size; i++) {
+               for (i = 0; i < reg_regdb_size; i++) {
                        curdom = reg_regdb[i];
 
-                       if (!memcmp(request->alpha2, curdom->alpha2, 2)) {
-                               r = reg_copy_regd(&regdom, curdom);
-                               if (r)
-                                       break;
-                               set_reg = true;
+                       if (alpha2_equal(request->alpha2, curdom->alpha2)) {
+                               regdom = reg_copy_regd(curdom);
                                break;
                        }
                }
@@ -376,7 +399,7 @@ static void reg_regdb_search(struct work_struct *work)
        }
        mutex_unlock(&reg_regdb_search_mutex);
 
-       if (set_reg)
+       if (!IS_ERR_OR_NULL(regdom))
                set_regdom(regdom);
 
        mutex_unlock(&cfg80211_mutex);
@@ -434,15 +457,14 @@ static int call_crda(const char *alpha2)
        return kobject_uevent(&reg_pdev->dev.kobj, KOBJ_CHANGE);
 }
 
-/* Used by nl80211 before kmalloc'ing our regulatory domain */
-bool reg_is_valid_request(const char *alpha2)
+static bool reg_is_valid_request(const char *alpha2)
 {
-       assert_cfg80211_lock();
+       struct regulatory_request *lr = get_last_request();
 
-       if (!last_request)
+       if (!lr || lr->processed)
                return false;
 
-       return alpha2_equal(last_request->alpha2, alpha2);
+       return alpha2_equal(lr->alpha2, alpha2);
 }
 
 /* Sanity check on a regulatory rule */
@@ -460,7 +482,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
        freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
 
        if (freq_range->end_freq_khz <= freq_range->start_freq_khz ||
-                       freq_range->max_bandwidth_khz > freq_diff)
+           freq_range->max_bandwidth_khz > freq_diff)
                return false;
 
        return true;
@@ -487,8 +509,7 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd)
 }
 
 static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range,
-                           u32 center_freq_khz,
-                           u32 bw_khz)
+                           u32 center_freq_khz, u32 bw_khz)
 {
        u32 start_freq_khz, end_freq_khz;
 
@@ -518,7 +539,7 @@ static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range,
  * regulatory rule support for other "bands".
  **/
 static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
-       u32 freq_khz)
+                             u32 freq_khz)
 {
 #define ONE_GHZ_IN_KHZ 1000000
        /*
@@ -540,10 +561,9 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
  * Helper for regdom_intersect(), this does the real
  * mathematical intersection fun
  */
-static int reg_rules_intersect(
-       const struct ieee80211_reg_rule *rule1,
-       const struct ieee80211_reg_rule *rule2,
-       struct ieee80211_reg_rule *intersected_rule)
+static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
+                              const struct ieee80211_reg_rule *rule2,
+                              struct ieee80211_reg_rule *intersected_rule)
 {
        const struct ieee80211_freq_range *freq_range1, *freq_range2;
        struct ieee80211_freq_range *freq_range;
@@ -560,11 +580,11 @@ static int reg_rules_intersect(
        power_rule = &intersected_rule->power_rule;
 
        freq_range->start_freq_khz = max(freq_range1->start_freq_khz,
-               freq_range2->start_freq_khz);
+                                        freq_range2->start_freq_khz);
        freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
-               freq_range2->end_freq_khz);
+                                      freq_range2->end_freq_khz);
        freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
-               freq_range2->max_bandwidth_khz);
+                                           freq_range2->max_bandwidth_khz);
 
        freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
        if (freq_range->max_bandwidth_khz > freq_diff)
@@ -575,7 +595,7 @@ static int reg_rules_intersect(
        power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
                power_rule2->max_antenna_gain);
 
-       intersected_rule->flags = (rule1->flags | rule2->flags);
+       intersected_rule->flags = rule1->flags | rule2->flags;
 
        if (!is_valid_reg_rule(intersected_rule))
                return -EINVAL;
@@ -596,9 +616,9 @@ static int reg_rules_intersect(
  * resulting intersection of rules between rd1 and rd2. We will
  * kzalloc() this structure for you.
  */
-static struct ieee80211_regdomain *regdom_intersect(
-       const struct ieee80211_regdomain *rd1,
-       const struct ieee80211_regdomain *rd2)
+static struct ieee80211_regdomain *
+regdom_intersect(const struct ieee80211_regdomain *rd1,
+                const struct ieee80211_regdomain *rd2)
 {
        int r, size_of_regd;
        unsigned int x, y;
@@ -607,12 +627,7 @@ static struct ieee80211_regdomain *regdom_intersect(
        struct ieee80211_reg_rule *intersected_rule;
        struct ieee80211_regdomain *rd;
        /* This is just a dummy holder to help us count */
-       struct ieee80211_reg_rule irule;
-
-       /* Uses the stack temporarily for counter arithmetic */
-       intersected_rule = &irule;
-
-       memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule));
+       struct ieee80211_reg_rule dummy_rule;
 
        if (!rd1 || !rd2)
                return NULL;
@@ -629,11 +644,8 @@ static struct ieee80211_regdomain *regdom_intersect(
                rule1 = &rd1->reg_rules[x];
                for (y = 0; y < rd2->n_reg_rules; y++) {
                        rule2 = &rd2->reg_rules[y];
-                       if (!reg_rules_intersect(rule1, rule2,
-                                       intersected_rule))
+                       if (!reg_rules_intersect(rule1, rule2, &dummy_rule))
                                num_rules++;
-                       memset(intersected_rule, 0,
-                                       sizeof(struct ieee80211_reg_rule));
                }
        }
 
@@ -641,15 +653,15 @@ static struct ieee80211_regdomain *regdom_intersect(
                return NULL;
 
        size_of_regd = sizeof(struct ieee80211_regdomain) +
-               ((num_rules + 1) * sizeof(struct ieee80211_reg_rule));
+                      num_rules * sizeof(struct ieee80211_reg_rule);
 
        rd = kzalloc(size_of_regd, GFP_KERNEL);
        if (!rd)
                return NULL;
 
-       for (x = 0; x < rd1->n_reg_rules; x++) {
+       for (x = 0; x < rd1->n_reg_rules && rule_idx < num_rules; x++) {
                rule1 = &rd1->reg_rules[x];
-               for (y = 0; y < rd2->n_reg_rules; y++) {
+               for (y = 0; y < rd2->n_reg_rules && rule_idx < num_rules; y++) {
                        rule2 = &rd2->reg_rules[y];
                        /*
                         * This time around instead of using the stack lets
@@ -657,8 +669,7 @@ static struct ieee80211_regdomain *regdom_intersect(
                         * a memcpy()
                         */
                        intersected_rule = &rd->reg_rules[rule_idx];
-                       r = reg_rules_intersect(rule1, rule2,
-                               intersected_rule);
+                       r = reg_rules_intersect(rule1, rule2, intersected_rule);
                        /*
                         * No need to memset here the intersected rule here as
                         * we're not using the stack anymore
@@ -699,34 +710,16 @@ static u32 map_regdom_flags(u32 rd_flags)
        return channel_flags;
 }
 
-static int freq_reg_info_regd(struct wiphy *wiphy,
-                             u32 center_freq,
-                             u32 desired_bw_khz,
-                             const struct ieee80211_reg_rule **reg_rule,
-                             const struct ieee80211_regdomain *custom_regd)
+static const struct ieee80211_reg_rule *
+freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
+                  const struct ieee80211_regdomain *regd)
 {
        int i;
        bool band_rule_found = false;
-       const struct ieee80211_regdomain *regd;
        bool bw_fits = false;
 
-       if (!desired_bw_khz)
-               desired_bw_khz = MHZ_TO_KHZ(20);
-
-       regd = custom_regd ? custom_regd : cfg80211_regdomain;
-
-       /*
-        * Follow the driver's regulatory domain, if present, unless a country
-        * IE has been processed or a user wants to help complaince further
-        */
-       if (!custom_regd &&
-           last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           last_request->initiator != NL80211_REGDOM_SET_BY_USER &&
-           wiphy->regd)
-               regd = wiphy->regd;
-
        if (!regd)
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
 
        for (i = 0; i < regd->n_reg_rules; i++) {
                const struct ieee80211_reg_rule *rr;
@@ -743,33 +736,36 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
                if (!band_rule_found)
                        band_rule_found = freq_in_rule_band(fr, center_freq);
 
-               bw_fits = reg_does_bw_fit(fr,
-                                         center_freq,
-                                         desired_bw_khz);
+               bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
 
-               if (band_rule_found && bw_fits) {
-                       *reg_rule = rr;
-                       return 0;
-               }
+               if (band_rule_found && bw_fits)
+                       return rr;
        }
 
        if (!band_rule_found)
-               return -ERANGE;
+               return ERR_PTR(-ERANGE);
 
-       return -EINVAL;
+       return ERR_PTR(-EINVAL);
 }
 
-int freq_reg_info(struct wiphy *wiphy,
-                 u32 center_freq,
-                 u32 desired_bw_khz,
-                 const struct ieee80211_reg_rule **reg_rule)
+const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
+                                              u32 center_freq)
 {
-       assert_cfg80211_lock();
-       return freq_reg_info_regd(wiphy,
-                                 center_freq,
-                                 desired_bw_khz,
-                                 reg_rule,
-                                 NULL);
+       const struct ieee80211_regdomain *regd;
+       struct regulatory_request *lr = get_last_request();
+
+       /*
+        * Follow the driver's regulatory domain, if present, unless a country
+        * IE has been processed or a user wants to help complaince further
+        */
+       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+           lr->initiator != NL80211_REGDOM_SET_BY_USER &&
+           wiphy->regd)
+               regd = get_wiphy_regdom(wiphy);
+       else
+               regd = get_cfg80211_regdom();
+
+       return freq_reg_info_regd(wiphy, center_freq, regd);
 }
 EXPORT_SYMBOL(freq_reg_info);
 
@@ -792,7 +788,6 @@ static const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
 }
 
 static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
-                                   u32 desired_bw_khz,
                                    const struct ieee80211_reg_rule *reg_rule)
 {
        const struct ieee80211_power_rule *power_rule;
@@ -807,21 +802,16 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
        else
                snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain);
 
-       REG_DBG_PRINT("Updating information on frequency %d MHz "
-                     "for a %d MHz width channel with regulatory rule:\n",
-                     chan->center_freq,
-                     KHZ_TO_MHZ(desired_bw_khz));
+       REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n",
+                     chan->center_freq);
 
        REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n",
-                     freq_range->start_freq_khz,
-                     freq_range->end_freq_khz,
-                     freq_range->max_bandwidth_khz,
-                     max_antenna_gain,
+                     freq_range->start_freq_khz, freq_range->end_freq_khz,
+                     freq_range->max_bandwidth_khz, max_antenna_gain,
                      power_rule->max_eirp);
 }
 #else
 static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
-                                   u32 desired_bw_khz,
                                    const struct ieee80211_reg_rule *reg_rule)
 {
        return;
@@ -831,43 +821,25 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
 /*
  * Note that right now we assume the desired channel bandwidth
  * is always 20 MHz for each individual channel (HT40 uses 20 MHz
- * per channel, the primary and the extension channel). To support
- * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a
- * new ieee80211_channel.target_bw and re run the regulatory check
- * on the wiphy with the target_bw specified. Then we can simply use
- * that below for the desired_bw_khz below.
+ * per channel, the primary and the extension channel).
  */
 static void handle_channel(struct wiphy *wiphy,
                           enum nl80211_reg_initiator initiator,
-                          enum ieee80211_band band,
-                          unsigned int chan_idx)
+                          struct ieee80211_channel *chan)
 {
-       int r;
        u32 flags, bw_flags = 0;
-       u32 desired_bw_khz = MHZ_TO_KHZ(20);
        const struct ieee80211_reg_rule *reg_rule = NULL;
        const struct ieee80211_power_rule *power_rule = NULL;
        const struct ieee80211_freq_range *freq_range = NULL;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *chan;
        struct wiphy *request_wiphy = NULL;
+       struct regulatory_request *lr = get_last_request();
 
-       assert_cfg80211_lock();
-
-       request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
-
-       sband = wiphy->bands[band];
-       BUG_ON(chan_idx >= sband->n_channels);
-       chan = &sband->channels[chan_idx];
+       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
 
        flags = chan->orig_flags;
 
-       r = freq_reg_info(wiphy,
-                         MHZ_TO_KHZ(chan->center_freq),
-                         desired_bw_khz,
-                         &reg_rule);
-
-       if (r) {
+       reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
+       if (IS_ERR(reg_rule)) {
                /*
                 * We will disable all channels that do not match our
                 * received regulatory rule unless the hint is coming
@@ -879,7 +851,7 @@ static void handle_channel(struct wiphy *wiphy,
                 * while 5 GHz is still supported.
                 */
                if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-                   r == -ERANGE)
+                   PTR_ERR(reg_rule) == -ERANGE)
                        return;
 
                REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);
@@ -887,7 +859,7 @@ static void handle_channel(struct wiphy *wiphy,
                return;
        }
 
-       chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule);
+       chan_reg_rule_print_dbg(chan, reg_rule);
 
        power_rule = &reg_rule->power_rule;
        freq_range = &reg_rule->freq_range;
@@ -895,7 +867,7 @@ static void handle_channel(struct wiphy *wiphy,
        if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
                bw_flags = IEEE80211_CHAN_NO_HT40;
 
-       if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+       if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
            request_wiphy && request_wiphy == wiphy &&
            request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
                /*
@@ -914,8 +886,9 @@ static void handle_channel(struct wiphy *wiphy,
 
        chan->beacon_found = false;
        chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
-       chan->max_antenna_gain = min(chan->orig_mag,
-               (int) MBI_TO_DBI(power_rule->max_antenna_gain));
+       chan->max_antenna_gain =
+               min_t(int, chan->orig_mag,
+                     MBI_TO_DBI(power_rule->max_antenna_gain));
        chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
        if (chan->orig_mpwr) {
                /*
@@ -935,68 +908,65 @@ static void handle_channel(struct wiphy *wiphy,
 }
 
 static void handle_band(struct wiphy *wiphy,
-                       enum ieee80211_band band,
-                       enum nl80211_reg_initiator initiator)
+                       enum nl80211_reg_initiator initiator,
+                       struct ieee80211_supported_band *sband)
 {
        unsigned int i;
-       struct ieee80211_supported_band *sband;
 
-       BUG_ON(!wiphy->bands[band]);
-       sband = wiphy->bands[band];
+       if (!sband)
+               return;
 
        for (i = 0; i < sband->n_channels; i++)
-               handle_channel(wiphy, initiator, band, i);
+               handle_channel(wiphy, initiator, &sband->channels[i]);
 }
 
 static bool reg_request_cell_base(struct regulatory_request *request)
 {
        if (request->initiator != NL80211_REGDOM_SET_BY_USER)
                return false;
-       if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
-               return false;
-       return true;
+       return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
 }
 
 bool reg_last_request_cell_base(void)
 {
        bool val;
-       assert_cfg80211_lock();
 
        mutex_lock(&reg_mutex);
-       val = reg_request_cell_base(last_request);
+       val = reg_request_cell_base(get_last_request());
        mutex_unlock(&reg_mutex);
+
        return val;
 }
 
 #ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
-
 /* Core specific check */
-static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
+static enum reg_request_treatment
+reg_ignore_cell_hint(struct regulatory_request *pending_request)
 {
+       struct regulatory_request *lr = get_last_request();
+
        if (!reg_num_devs_support_basehint)
-               return -EOPNOTSUPP;
+               return REG_REQ_IGNORE;
 
-       if (reg_request_cell_base(last_request)) {
-               if (!regdom_changes(pending_request->alpha2))
-                       return -EALREADY;
-               return 0;
-       }
-       return 0;
+       if (reg_request_cell_base(lr) &&
+           !regdom_changes(pending_request->alpha2))
+               return REG_REQ_ALREADY_SET;
+
+       return REG_REQ_OK;
 }
 
 /* Device specific check */
 static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
 {
-       if (!(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS))
-               return true;
-       return false;
+       return !(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS);
 }
 #else
 static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
 {
-       return -EOPNOTSUPP;
+       return REG_REQ_IGNORE;
 }
-static int reg_dev_ignore_cell_hint(struct wiphy *wiphy)
+
+static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
 {
        return true;
 }
@@ -1006,18 +976,17 @@ static int reg_dev_ignore_cell_hint(struct wiphy *wiphy)
 static bool ignore_reg_update(struct wiphy *wiphy,
                              enum nl80211_reg_initiator initiator)
 {
-       if (!last_request) {
-               REG_DBG_PRINT("Ignoring regulatory request %s since "
-                             "last_request is not set\n",
+       struct regulatory_request *lr = get_last_request();
+
+       if (!lr) {
+               REG_DBG_PRINT("Ignoring regulatory request %s since last_request is not set\n",
                              reg_initiator_name(initiator));
                return true;
        }
 
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
            wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
-               REG_DBG_PRINT("Ignoring regulatory request %s "
-                             "since the driver uses its own custom "
-                             "regulatory domain\n",
+               REG_DBG_PRINT("Ignoring regulatory request %s since the driver uses its own custom regulatory domain\n",
                              reg_initiator_name(initiator));
                return true;
        }
@@ -1028,22 +997,35 @@ static bool ignore_reg_update(struct wiphy *wiphy,
         */
        if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd &&
            initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           !is_world_regdom(last_request->alpha2)) {
-               REG_DBG_PRINT("Ignoring regulatory request %s "
-                             "since the driver requires its own regulatory "
-                             "domain to be set first\n",
+           !is_world_regdom(lr->alpha2)) {
+               REG_DBG_PRINT("Ignoring regulatory request %s since the driver requires its own regulatory domain to be set first\n",
                              reg_initiator_name(initiator));
                return true;
        }
 
-       if (reg_request_cell_base(last_request))
+       if (reg_request_cell_base(lr))
                return reg_dev_ignore_cell_hint(wiphy);
 
        return false;
 }
 
-static void handle_reg_beacon(struct wiphy *wiphy,
-                             unsigned int chan_idx,
+static bool reg_is_world_roaming(struct wiphy *wiphy)
+{
+       const struct ieee80211_regdomain *cr = get_cfg80211_regdom();
+       const struct ieee80211_regdomain *wr = get_wiphy_regdom(wiphy);
+       struct regulatory_request *lr = get_last_request();
+
+       if (is_world_regdom(cr->alpha2) || (wr && is_world_regdom(wr->alpha2)))
+               return true;
+
+       if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+               return true;
+
+       return false;
+}
+
+static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
                              struct reg_beacon *reg_beacon)
 {
        struct ieee80211_supported_band *sband;
@@ -1051,8 +1033,6 @@ static void handle_reg_beacon(struct wiphy *wiphy,
        bool channel_changed = false;
        struct ieee80211_channel chan_before;
 
-       assert_cfg80211_lock();
-
        sband = wiphy->bands[reg_beacon->chan.band];
        chan = &sband->channels[chan_idx];
 
@@ -1064,6 +1044,9 @@ static void handle_reg_beacon(struct wiphy *wiphy,
 
        chan->beacon_found = true;
 
+       if (!reg_is_world_roaming(wiphy))
+               return;
+
        if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
                return;
 
@@ -1094,8 +1077,6 @@ static void wiphy_update_new_beacon(struct wiphy *wiphy,
        unsigned int i;
        struct ieee80211_supported_band *sband;
 
-       assert_cfg80211_lock();
-
        if (!wiphy->bands[reg_beacon->chan.band])
                return;
 
@@ -1114,11 +1095,6 @@ static void wiphy_update_beacon_reg(struct wiphy *wiphy)
        struct ieee80211_supported_band *sband;
        struct reg_beacon *reg_beacon;
 
-       assert_cfg80211_lock();
-
-       if (list_empty(&reg_beacon_list))
-               return;
-
        list_for_each_entry(reg_beacon, &reg_beacon_list, list) {
                if (!wiphy->bands[reg_beacon->chan.band])
                        continue;
@@ -1128,18 +1104,6 @@ static void wiphy_update_beacon_reg(struct wiphy *wiphy)
        }
 }
 
-static bool reg_is_world_roaming(struct wiphy *wiphy)
-{
-       if (is_world_regdom(cfg80211_regdomain->alpha2) ||
-           (wiphy->regd && is_world_regdom(wiphy->regd->alpha2)))
-               return true;
-       if (last_request &&
-           last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
-               return true;
-       return false;
-}
-
 /* Reap the advantages of previously found beacons */
 static void reg_process_beacons(struct wiphy *wiphy)
 {
@@ -1149,39 +1113,29 @@ static void reg_process_beacons(struct wiphy *wiphy)
         */
        if (!last_request)
                return;
-       if (!reg_is_world_roaming(wiphy))
-               return;
        wiphy_update_beacon_reg(wiphy);
 }
 
-static bool is_ht40_not_allowed(struct ieee80211_channel *chan)
+static bool is_ht40_allowed(struct ieee80211_channel *chan)
 {
        if (!chan)
-               return true;
+               return false;
        if (chan->flags & IEEE80211_CHAN_DISABLED)
-               return true;
+               return false;
        /* This would happen when regulatory rules disallow HT40 completely */
-       if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40)))
-               return true;
-       return false;
+       if ((chan->flags & IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40)
+               return false;
+       return true;
 }
 
 static void reg_process_ht_flags_channel(struct wiphy *wiphy,
-                                        enum ieee80211_band band,
-                                        unsigned int chan_idx)
+                                        struct ieee80211_channel *channel)
 {
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *channel;
+       struct ieee80211_supported_band *sband = wiphy->bands[channel->band];
        struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
        unsigned int i;
 
-       assert_cfg80211_lock();
-
-       sband = wiphy->bands[band];
-       BUG_ON(chan_idx >= sband->n_channels);
-       channel = &sband->channels[chan_idx];
-
-       if (is_ht40_not_allowed(channel)) {
+       if (!is_ht40_allowed(channel)) {
                channel->flags |= IEEE80211_CHAN_NO_HT40;
                return;
        }
@@ -1192,6 +1146,7 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
         */
        for (i = 0; i < sband->n_channels; i++) {
                struct ieee80211_channel *c = &sband->channels[i];
+
                if (c->center_freq == (channel->center_freq - 20))
                        channel_before = c;
                if (c->center_freq == (channel->center_freq + 20))
@@ -1203,28 +1158,27 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
         * if that ever changes we also need to change the below logic
         * to include that as well.
         */
-       if (is_ht40_not_allowed(channel_before))
+       if (!is_ht40_allowed(channel_before))
                channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
        else
                channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
 
-       if (is_ht40_not_allowed(channel_after))
+       if (!is_ht40_allowed(channel_after))
                channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
        else
                channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
 }
 
 static void reg_process_ht_flags_band(struct wiphy *wiphy,
-                                     enum ieee80211_band band)
+                                     struct ieee80211_supported_band *sband)
 {
        unsigned int i;
-       struct ieee80211_supported_band *sband;
 
-       BUG_ON(!wiphy->bands[band]);
-       sband = wiphy->bands[band];
+       if (!sband)
+               return;
 
        for (i = 0; i < sband->n_channels; i++)
-               reg_process_ht_flags_channel(wiphy, band, i);
+               reg_process_ht_flags_channel(wiphy, &sband->channels[i]);
 }
 
 static void reg_process_ht_flags(struct wiphy *wiphy)
@@ -1234,34 +1188,29 @@ static void reg_process_ht_flags(struct wiphy *wiphy)
        if (!wiphy)
                return;
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               if (wiphy->bands[band])
-                       reg_process_ht_flags_band(wiphy, band);
-       }
-
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+               reg_process_ht_flags_band(wiphy, wiphy->bands[band]);
 }
 
 static void wiphy_update_regulatory(struct wiphy *wiphy,
                                    enum nl80211_reg_initiator initiator)
 {
        enum ieee80211_band band;
-
-       assert_reg_lock();
+       struct regulatory_request *lr = get_last_request();
 
        if (ignore_reg_update(wiphy, initiator))
                return;
 
-       last_request->dfs_region = cfg80211_regdomain->dfs_region;
+       lr->dfs_region = get_cfg80211_regdom()->dfs_region;
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               if (wiphy->bands[band])
-                       handle_band(wiphy, band, initiator);
-       }
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+               handle_band(wiphy, initiator, wiphy->bands[band]);
 
        reg_process_beacons(wiphy);
        reg_process_ht_flags(wiphy);
+
        if (wiphy->reg_notifier)
-               wiphy->reg_notifier(wiphy, last_request);
+               wiphy->reg_notifier(wiphy, lr);
 }
 
 static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
@@ -1269,6 +1218,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
        struct cfg80211_registered_device *rdev;
        struct wiphy *wiphy;
 
+       assert_cfg80211_lock();
+
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
                wiphy = &rdev->wiphy;
                wiphy_update_regulatory(wiphy, initiator);
@@ -1280,47 +1231,30 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
                if (initiator == NL80211_REGDOM_SET_BY_CORE &&
                    wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
                    wiphy->reg_notifier)
-                       wiphy->reg_notifier(wiphy, last_request);
+                       wiphy->reg_notifier(wiphy, get_last_request());
        }
 }
 
 static void handle_channel_custom(struct wiphy *wiphy,
-                                 enum ieee80211_band band,
-                                 unsigned int chan_idx,
+                                 struct ieee80211_channel *chan,
                                  const struct ieee80211_regdomain *regd)
 {
-       int r;
-       u32 desired_bw_khz = MHZ_TO_KHZ(20);
        u32 bw_flags = 0;
        const struct ieee80211_reg_rule *reg_rule = NULL;
        const struct ieee80211_power_rule *power_rule = NULL;
        const struct ieee80211_freq_range *freq_range = NULL;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *chan;
-
-       assert_reg_lock();
 
-       sband = wiphy->bands[band];
-       BUG_ON(chan_idx >= sband->n_channels);
-       chan = &sband->channels[chan_idx];
-
-       r = freq_reg_info_regd(wiphy,
-                              MHZ_TO_KHZ(chan->center_freq),
-                              desired_bw_khz,
-                              &reg_rule,
-                              regd);
+       reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
+                                     regd);
 
-       if (r) {
-               REG_DBG_PRINT("Disabling freq %d MHz as custom "
-                             "regd has no rule that fits a %d MHz "
-                             "wide channel\n",
-                             chan->center_freq,
-                             KHZ_TO_MHZ(desired_bw_khz));
+       if (IS_ERR(reg_rule)) {
+               REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
+                             chan->center_freq);
                chan->flags = IEEE80211_CHAN_DISABLED;
                return;
        }
 
-       chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule);
+       chan_reg_rule_print_dbg(chan, reg_rule);
 
        power_rule = &reg_rule->power_rule;
        freq_range = &reg_rule->freq_range;
@@ -1334,17 +1268,17 @@ static void handle_channel_custom(struct wiphy *wiphy,
                (int) MBM_TO_DBM(power_rule->max_eirp);
 }
 
-static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band,
+static void handle_band_custom(struct wiphy *wiphy,
+                              struct ieee80211_supported_band *sband,
                               const struct ieee80211_regdomain *regd)
 {
        unsigned int i;
-       struct ieee80211_supported_band *sband;
 
-       BUG_ON(!wiphy->bands[band]);
-       sband = wiphy->bands[band];
+       if (!sband)
+               return;
 
        for (i = 0; i < sband->n_channels; i++)
-               handle_channel_custom(wiphy, band, i, regd);
+               handle_channel_custom(wiphy, &sband->channels[i], regd);
 }
 
 /* Used by drivers prior to wiphy registration */
@@ -1354,60 +1288,50 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
        enum ieee80211_band band;
        unsigned int bands_set = 0;
 
-       mutex_lock(&reg_mutex);
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (!wiphy->bands[band])
                        continue;
-               handle_band_custom(wiphy, band, regd);
+               handle_band_custom(wiphy, wiphy->bands[band], regd);
                bands_set++;
        }
-       mutex_unlock(&reg_mutex);
 
        /*
         * no point in calling this if it won't have any effect
-        * on your device's supportd bands.
+        * on your device's supported bands.
         */
        WARN_ON(!bands_set);
 }
 EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
 
-/*
- * Return value which can be used by ignore_request() to indicate
- * it has been determined we should intersect two regulatory domains
- */
-#define REG_INTERSECT  1
-
 /* This has the logic which determines when a new request
  * should be ignored. */
-static int ignore_request(struct wiphy *wiphy,
+static enum reg_request_treatment
+get_reg_request_treatment(struct wiphy *wiphy,
                          struct regulatory_request *pending_request)
 {
        struct wiphy *last_wiphy = NULL;
-
-       assert_cfg80211_lock();
+       struct regulatory_request *lr = get_last_request();
 
        /* All initial requests are respected */
-       if (!last_request)
-               return 0;
+       if (!lr)
+               return REG_REQ_OK;
 
        switch (pending_request->initiator) {
        case NL80211_REGDOM_SET_BY_CORE:
-               return 0;
+               return REG_REQ_OK;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
-
-               if (reg_request_cell_base(last_request)) {
+               if (reg_request_cell_base(lr)) {
                        /* Trust a Cell base station over the AP's country IE */
                        if (regdom_changes(pending_request->alpha2))
-                               return -EOPNOTSUPP;
-                       return -EALREADY;
+                               return REG_REQ_IGNORE;
+                       return REG_REQ_ALREADY_SET;
                }
 
-               last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+               last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
 
                if (unlikely(!is_an_alpha2(pending_request->alpha2)))
                        return -EINVAL;
-               if (last_request->initiator ==
-                   NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+               if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                        if (last_wiphy != wiphy) {
                                /*
                                 * Two cards with two APs claiming different
@@ -1416,23 +1340,23 @@ static int ignore_request(struct wiphy *wiphy,
                                 * to be correct. Reject second one for now.
                                 */
                                if (regdom_changes(pending_request->alpha2))
-                                       return -EOPNOTSUPP;
-                               return -EALREADY;
+                                       return REG_REQ_IGNORE;
+                               return REG_REQ_ALREADY_SET;
                        }
                        /*
                         * Two consecutive Country IE hints on the same wiphy.
                         * This should be picked up early by the driver/stack
                         */
                        if (WARN_ON(regdom_changes(pending_request->alpha2)))
-                               return 0;
-                       return -EALREADY;
+                               return REG_REQ_OK;
+                       return REG_REQ_ALREADY_SET;
                }
                return 0;
        case NL80211_REGDOM_SET_BY_DRIVER:
-               if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
+               if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
                        if (regdom_changes(pending_request->alpha2))
-                               return 0;
-                       return -EALREADY;
+                               return REG_REQ_OK;
+                       return REG_REQ_ALREADY_SET;
                }
 
                /*
@@ -1440,59 +1364,59 @@ static int ignore_request(struct wiphy *wiphy,
                 * back in or if you add a new device for which the previously
                 * loaded card also agrees on the regulatory domain.
                 */
-               if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
                    !regdom_changes(pending_request->alpha2))
-                       return -EALREADY;
+                       return REG_REQ_ALREADY_SET;
 
-               return REG_INTERSECT;
+               return REG_REQ_INTERSECT;
        case NL80211_REGDOM_SET_BY_USER:
                if (reg_request_cell_base(pending_request))
                        return reg_ignore_cell_hint(pending_request);
 
-               if (reg_request_cell_base(last_request))
-                       return -EOPNOTSUPP;
+               if (reg_request_cell_base(lr))
+                       return REG_REQ_IGNORE;
 
-               if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
-                       return REG_INTERSECT;
+               if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
+                       return REG_REQ_INTERSECT;
                /*
                 * If the user knows better the user should set the regdom
                 * to their country before the IE is picked up
                 */
-               if (last_request->initiator == NL80211_REGDOM_SET_BY_USER &&
-                         last_request->intersect)
-                       return -EOPNOTSUPP;
+               if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
+                   lr->intersect)
+                       return REG_REQ_IGNORE;
                /*
                 * Process user requests only after previous user/driver/core
                 * requests have been processed
                 */
-               if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE ||
-                   last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-                   last_request->initiator == NL80211_REGDOM_SET_BY_USER) {
-                       if (regdom_changes(last_request->alpha2))
-                               return -EAGAIN;
-               }
+               if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||
+                    lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+                    lr->initiator == NL80211_REGDOM_SET_BY_USER) &&
+                   regdom_changes(lr->alpha2))
+                       return REG_REQ_IGNORE;
 
                if (!regdom_changes(pending_request->alpha2))
-                       return -EALREADY;
+                       return REG_REQ_ALREADY_SET;
 
-               return 0;
+               return REG_REQ_OK;
        }
 
-       return -EINVAL;
+       return REG_REQ_IGNORE;
 }
 
 static void reg_set_request_processed(void)
 {
        bool need_more_processing = false;
+       struct regulatory_request *lr = get_last_request();
 
-       last_request->processed = true;
+       lr->processed = true;
 
        spin_lock(&reg_requests_lock);
        if (!list_empty(&reg_requests_list))
                need_more_processing = true;
        spin_unlock(&reg_requests_lock);
 
-       if (last_request->initiator == NL80211_REGDOM_SET_BY_USER)
+       if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
                cancel_delayed_work(&reg_timeout);
 
        if (need_more_processing)
@@ -1508,116 +1432,122 @@ static void reg_set_request_processed(void)
  * The Wireless subsystem can use this function to hint to the wireless core
  * what it believes should be the current regulatory domain.
  *
- * Returns zero if all went fine, %-EALREADY if a regulatory domain had
- * already been set or other standard error codes.
+ * Returns one of the different reg request treatment values.
  *
- * Caller must hold &cfg80211_mutex and &reg_mutex
+ * Caller must hold &reg_mutex
  */
-static int __regulatory_hint(struct wiphy *wiphy,
-                            struct regulatory_request *pending_request)
+static enum reg_request_treatment
+__regulatory_hint(struct wiphy *wiphy,
+                 struct regulatory_request *pending_request)
 {
+       const struct ieee80211_regdomain *regd;
        bool intersect = false;
-       int r = 0;
-
-       assert_cfg80211_lock();
+       enum reg_request_treatment treatment;
+       struct regulatory_request *lr;
 
-       r = ignore_request(wiphy, pending_request);
+       treatment = get_reg_request_treatment(wiphy, pending_request);
 
-       if (r == REG_INTERSECT) {
+       switch (treatment) {
+       case REG_REQ_INTERSECT:
                if (pending_request->initiator ==
                    NL80211_REGDOM_SET_BY_DRIVER) {
-                       r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
-                       if (r) {
+                       regd = reg_copy_regd(get_cfg80211_regdom());
+                       if (IS_ERR(regd)) {
                                kfree(pending_request);
-                               return r;
+                               return PTR_ERR(regd);
                        }
+                       rcu_assign_pointer(wiphy->regd, regd);
                }
                intersect = true;
-       } else if (r) {
+               break;
+       case REG_REQ_OK:
+               break;
+       default:
                /*
                 * If the regulatory domain being requested by the
                 * driver has already been set just copy it to the
                 * wiphy
                 */
-               if (r == -EALREADY &&
-                   pending_request->initiator ==
-                   NL80211_REGDOM_SET_BY_DRIVER) {
-                       r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
-                       if (r) {
+               if (treatment == REG_REQ_ALREADY_SET &&
+                   pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
+                       regd = reg_copy_regd(get_cfg80211_regdom());
+                       if (IS_ERR(regd)) {
                                kfree(pending_request);
-                               return r;
+                               return REG_REQ_IGNORE;
                        }
-                       r = -EALREADY;
+                       treatment = REG_REQ_ALREADY_SET;
+                       rcu_assign_pointer(wiphy->regd, regd);
                        goto new_request;
                }
                kfree(pending_request);
-               return r;
+               return treatment;
        }
 
 new_request:
-       if (last_request != &core_request_world)
-               kfree(last_request);
+       lr = get_last_request();
+       if (lr != &core_request_world && lr)
+               kfree_rcu(lr, rcu_head);
 
-       last_request = pending_request;
-       last_request->intersect = intersect;
+       pending_request->intersect = intersect;
+       pending_request->processed = false;
+       rcu_assign_pointer(last_request, pending_request);
+       lr = pending_request;
 
        pending_request = NULL;
 
-       if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) {
-               user_alpha2[0] = last_request->alpha2[0];
-               user_alpha2[1] = last_request->alpha2[1];
+       if (lr->initiator == NL80211_REGDOM_SET_BY_USER) {
+               user_alpha2[0] = lr->alpha2[0];
+               user_alpha2[1] = lr->alpha2[1];
        }
 
-       /* When r == REG_INTERSECT we do need to call CRDA */
-       if (r < 0) {
+       /* When r == REG_REQ_INTERSECT we do need to call CRDA */
+       if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) {
                /*
                 * Since CRDA will not be called in this case as we already
                 * have applied the requested regulatory domain before we just
                 * inform userspace we have processed the request
                 */
-               if (r == -EALREADY) {
-                       nl80211_send_reg_change_event(last_request);
+               if (treatment == REG_REQ_ALREADY_SET) {
+                       nl80211_send_reg_change_event(lr);
                        reg_set_request_processed();
                }
-               return r;
+               return treatment;
        }
 
-       return call_crda(last_request->alpha2);
+       if (call_crda(lr->alpha2))
+               return REG_REQ_IGNORE;
+       return REG_REQ_OK;
 }
 
 /* This processes *all* regulatory hints */
 static void reg_process_hint(struct regulatory_request *reg_request,
                             enum nl80211_reg_initiator reg_initiator)
 {
-       int r = 0;
        struct wiphy *wiphy = NULL;
 
-       BUG_ON(!reg_request->alpha2);
+       if (WARN_ON(!reg_request->alpha2))
+               return;
 
-       if (wiphy_idx_valid(reg_request->wiphy_idx))
+       if (reg_request->wiphy_idx != WIPHY_IDX_INVALID)
                wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
 
-       if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER &&
-           !wiphy) {
+       if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {
                kfree(reg_request);
                return;
        }
 
-       r = __regulatory_hint(wiphy, reg_request);
-       /* This is required so that the orig_* parameters are saved */
-       if (r == -EALREADY && wiphy &&
-           wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
-               wiphy_update_regulatory(wiphy, reg_initiator);
-               return;
+       switch (__regulatory_hint(wiphy, reg_request)) {
+       case REG_REQ_ALREADY_SET:
+               /* This is required so that the orig_* parameters are saved */
+               if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+                       wiphy_update_regulatory(wiphy, reg_initiator);
+               break;
+       default:
+               if (reg_initiator == NL80211_REGDOM_SET_BY_USER)
+                       schedule_delayed_work(&reg_timeout,
+                                             msecs_to_jiffies(3142));
+               break;
        }
-
-       /*
-        * We only time out user hints, given that they should be the only
-        * source of bogus requests.
-        */
-       if (r != -EALREADY &&
-           reg_initiator == NL80211_REGDOM_SET_BY_USER)
-               schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
 }
 
 /*
@@ -1627,15 +1557,15 @@ static void reg_process_hint(struct regulatory_request *reg_request,
  */
 static void reg_process_pending_hints(void)
 {
-       struct regulatory_request *reg_request;
+       struct regulatory_request *reg_request, *lr;
 
        mutex_lock(&cfg80211_mutex);
        mutex_lock(&reg_mutex);
+       lr = get_last_request();
 
        /* When last_request->processed becomes true this will be rescheduled */
-       if (last_request && !last_request->processed) {
-               REG_DBG_PRINT("Pending regulatory request, waiting "
-                             "for it to be processed...\n");
+       if (lr && !lr->processed) {
+               REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n");
                goto out;
        }
 
@@ -1666,23 +1596,14 @@ static void reg_process_pending_beacon_hints(void)
        struct cfg80211_registered_device *rdev;
        struct reg_beacon *pending_beacon, *tmp;
 
-       /*
-        * No need to hold the reg_mutex here as we just touch wiphys
-        * and do not read or access regulatory variables.
-        */
        mutex_lock(&cfg80211_mutex);
+       mutex_lock(&reg_mutex);
 
        /* This goes through the _pending_ beacon list */
        spin_lock_bh(&reg_pending_beacons_lock);
 
-       if (list_empty(&reg_pending_beacons)) {
-               spin_unlock_bh(&reg_pending_beacons_lock);
-               goto out;
-       }
-
        list_for_each_entry_safe(pending_beacon, tmp,
                                 &reg_pending_beacons, list) {
-
                list_del_init(&pending_beacon->list);
 
                /* Applies the beacon hint to current wiphys */
@@ -1694,7 +1615,7 @@ static void reg_process_pending_beacon_hints(void)
        }
 
        spin_unlock_bh(&reg_pending_beacons_lock);
-out:
+       mutex_unlock(&reg_mutex);
        mutex_unlock(&cfg80211_mutex);
 }
 
@@ -1706,10 +1627,8 @@ static void reg_todo(struct work_struct *work)
 
 static void queue_regulatory_request(struct regulatory_request *request)
 {
-       if (isalpha(request->alpha2[0]))
-               request->alpha2[0] = toupper(request->alpha2[0]);
-       if (isalpha(request->alpha2[1]))
-               request->alpha2[1] = toupper(request->alpha2[1]);
+       request->alpha2[0] = toupper(request->alpha2[0]);
+       request->alpha2[1] = toupper(request->alpha2[1]);
 
        spin_lock(&reg_requests_lock);
        list_add_tail(&request->list, &reg_requests_list);
@@ -1726,8 +1645,7 @@ static int regulatory_hint_core(const char *alpha2)
 {
        struct regulatory_request *request;
 
-       request = kzalloc(sizeof(struct regulatory_request),
-                         GFP_KERNEL);
+       request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
        if (!request)
                return -ENOMEM;
 
@@ -1746,13 +1664,14 @@ int regulatory_hint_user(const char *alpha2,
 {
        struct regulatory_request *request;
 
-       BUG_ON(!alpha2);
+       if (WARN_ON(!alpha2))
+               return -EINVAL;
 
        request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
        if (!request)
                return -ENOMEM;
 
-       request->wiphy_idx = WIPHY_IDX_STALE;
+       request->wiphy_idx = WIPHY_IDX_INVALID;
        request->alpha2[0] = alpha2[0];
        request->alpha2[1] = alpha2[1];
        request->initiator = NL80211_REGDOM_SET_BY_USER;
@@ -1768,8 +1687,8 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
 {
        struct regulatory_request *request;
 
-       BUG_ON(!alpha2);
-       BUG_ON(!wiphy);
+       if (WARN_ON(!alpha2 || !wiphy))
+               return -EINVAL;
 
        request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
        if (!request)
@@ -1777,9 +1696,6 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
 
        request->wiphy_idx = get_wiphy_idx(wiphy);
 
-       /* Must have registered wiphy first */
-       BUG_ON(!wiphy_idx_valid(request->wiphy_idx));
-
        request->alpha2[0] = alpha2[0];
        request->alpha2[1] = alpha2[1];
        request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
@@ -1794,18 +1710,17 @@ EXPORT_SYMBOL(regulatory_hint);
  * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and
  * therefore cannot iterate over the rdev list here.
  */
-void regulatory_hint_11d(struct wiphy *wiphy,
-                        enum ieee80211_band band,
-                        const u8 *country_ie,
-                        u8 country_ie_len)
+void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band,
+                        const u8 *country_ie, u8 country_ie_len)
 {
        char alpha2[2];
        enum environment_cap env = ENVIRON_ANY;
-       struct regulatory_request *request;
+       struct regulatory_request *request, *lr;
 
        mutex_lock(&reg_mutex);
+       lr = get_last_request();
 
-       if (unlikely(!last_request))
+       if (unlikely(!lr))
                goto out;
 
        /* IE len must be evenly divisible by 2 */
@@ -1828,9 +1743,8 @@ void regulatory_hint_11d(struct wiphy *wiphy,
         * We leave conflict resolution to the workqueue, where can hold
         * cfg80211_mutex.
         */
-       if (likely(last_request->initiator ==
-           NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           wiphy_idx_valid(last_request->wiphy_idx)))
+       if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+           lr->wiphy_idx != WIPHY_IDX_INVALID)
                goto out;
 
        request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
@@ -1843,12 +1757,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
        request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE;
        request->country_ie_env = env;
 
-       mutex_unlock(&reg_mutex);
-
        queue_regulatory_request(request);
-
-       return;
-
 out:
        mutex_unlock(&reg_mutex);
 }
@@ -1863,8 +1772,7 @@ static void restore_alpha2(char *alpha2, bool reset_user)
        if (is_user_regdom_saved()) {
                /* Unless we're asked to ignore it and reset it */
                if (reset_user) {
-                       REG_DBG_PRINT("Restoring regulatory settings "
-                              "including user preference\n");
+                       REG_DBG_PRINT("Restoring regulatory settings including user preference\n");
                        user_alpha2[0] = '9';
                        user_alpha2[1] = '7';
 
@@ -1874,26 +1782,20 @@ static void restore_alpha2(char *alpha2, bool reset_user)
                         * back as they were for a full restore.
                         */
                        if (!is_world_regdom(ieee80211_regdom)) {
-                               REG_DBG_PRINT("Keeping preference on "
-                                      "module parameter ieee80211_regdom: %c%c\n",
-                                      ieee80211_regdom[0],
-                                      ieee80211_regdom[1]);
+                               REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
+                                             ieee80211_regdom[0], ieee80211_regdom[1]);
                                alpha2[0] = ieee80211_regdom[0];
                                alpha2[1] = ieee80211_regdom[1];
                        }
                } else {
-                       REG_DBG_PRINT("Restoring regulatory settings "
-                              "while preserving user preference for: %c%c\n",
-                              user_alpha2[0],
-                              user_alpha2[1]);
+                       REG_DBG_PRINT("Restoring regulatory settings while preserving user preference for: %c%c\n",
+                                     user_alpha2[0], user_alpha2[1]);
                        alpha2[0] = user_alpha2[0];
                        alpha2[1] = user_alpha2[1];
                }
        } else if (!is_world_regdom(ieee80211_regdom)) {
-               REG_DBG_PRINT("Keeping preference on "
-                      "module parameter ieee80211_regdom: %c%c\n",
-                      ieee80211_regdom[0],
-                      ieee80211_regdom[1]);
+               REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
+                             ieee80211_regdom[0], ieee80211_regdom[1]);
                alpha2[0] = ieee80211_regdom[0];
                alpha2[1] = ieee80211_regdom[1];
        } else
@@ -1948,7 +1850,7 @@ static void restore_regulatory_settings(bool reset_user)
        mutex_lock(&cfg80211_mutex);
        mutex_lock(&reg_mutex);
 
-       reset_regdomains(true);
+       reset_regdomains(true, &world_regdom);
        restore_alpha2(alpha2, reset_user);
 
        /*
@@ -1958,49 +1860,35 @@ static void restore_regulatory_settings(bool reset_user)
         * settings.
         */
        spin_lock(&reg_requests_lock);
-       if (!list_empty(&reg_requests_list)) {
-               list_for_each_entry_safe(reg_request, tmp,
-                                        &reg_requests_list, list) {
-                       if (reg_request->initiator !=
-                           NL80211_REGDOM_SET_BY_USER)
-                               continue;
-                       list_move_tail(&reg_request->list, &tmp_reg_req_list);
-               }
+       list_for_each_entry_safe(reg_request, tmp, &reg_requests_list, list) {
+               if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER)
+                       continue;
+               list_move_tail(&reg_request->list, &tmp_reg_req_list);
        }
        spin_unlock(&reg_requests_lock);
 
        /* Clear beacon hints */
        spin_lock_bh(&reg_pending_beacons_lock);
-       if (!list_empty(&reg_pending_beacons)) {
-               list_for_each_entry_safe(reg_beacon, btmp,
-                                        &reg_pending_beacons, list) {
-                       list_del(&reg_beacon->list);
-                       kfree(reg_beacon);
-               }
+       list_for_each_entry_safe(reg_beacon, btmp, &reg_pending_beacons, list) {
+               list_del(&reg_beacon->list);
+               kfree(reg_beacon);
        }
        spin_unlock_bh(&reg_pending_beacons_lock);
 
-       if (!list_empty(&reg_beacon_list)) {
-               list_for_each_entry_safe(reg_beacon, btmp,
-                                        &reg_beacon_list, list) {
-                       list_del(&reg_beacon->list);
-                       kfree(reg_beacon);
-               }
+       list_for_each_entry_safe(reg_beacon, btmp, &reg_beacon_list, list) {
+               list_del(&reg_beacon->list);
+               kfree(reg_beacon);
        }
 
        /* First restore to the basic regulatory settings */
-       cfg80211_regdomain = cfg80211_world_regdom;
-       world_alpha2[0] = cfg80211_regdomain->alpha2[0];
-       world_alpha2[1] = cfg80211_regdomain->alpha2[1];
+       world_alpha2[0] = cfg80211_world_regdom->alpha2[0];
+       world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
                if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY)
                        restore_custom_reg_settings(&rdev->wiphy);
        }
 
-       mutex_unlock(&reg_mutex);
-       mutex_unlock(&cfg80211_mutex);
-
        regulatory_hint_core(world_alpha2);
 
        /*
@@ -2011,20 +1899,8 @@ static void restore_regulatory_settings(bool reset_user)
        if (is_an_alpha2(alpha2))
                regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER);
 
-       if (list_empty(&tmp_reg_req_list))
-               return;
-
-       mutex_lock(&cfg80211_mutex);
-       mutex_lock(&reg_mutex);
-
        spin_lock(&reg_requests_lock);
-       list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) {
-               REG_DBG_PRINT("Adding request for country %c%c back "
-                             "into the queue\n",
-                             reg_request->alpha2[0],
-                             reg_request->alpha2[1]);
-               list_move_tail(&reg_request->list, &reg_requests_list);
-       }
+       list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list);
        spin_unlock(&reg_requests_lock);
 
        mutex_unlock(&reg_mutex);
@@ -2037,8 +1913,7 @@ static void restore_regulatory_settings(bool reset_user)
 
 void regulatory_hint_disconnect(void)
 {
-       REG_DBG_PRINT("All devices are disconnected, going to "
-                     "restore regulatory settings\n");
+       REG_DBG_PRINT("All devices are disconnected, going to restore regulatory settings\n");
        restore_regulatory_settings(false);
 }
 
@@ -2051,31 +1926,48 @@ static bool freq_is_chan_12_13_14(u16 freq)
        return false;
 }
 
+static bool pending_reg_beacon(struct ieee80211_channel *beacon_chan)
+{
+       struct reg_beacon *pending_beacon;
+
+       list_for_each_entry(pending_beacon, &reg_pending_beacons, list)
+               if (beacon_chan->center_freq ==
+                   pending_beacon->chan.center_freq)
+                       return true;
+       return false;
+}
+
 int regulatory_hint_found_beacon(struct wiphy *wiphy,
                                 struct ieee80211_channel *beacon_chan,
                                 gfp_t gfp)
 {
        struct reg_beacon *reg_beacon;
+       bool processing;
 
-       if (likely((beacon_chan->beacon_found ||
-           (beacon_chan->flags & IEEE80211_CHAN_RADAR) ||
+       if (beacon_chan->beacon_found ||
+           beacon_chan->flags & IEEE80211_CHAN_RADAR ||
            (beacon_chan->band == IEEE80211_BAND_2GHZ &&
-            !freq_is_chan_12_13_14(beacon_chan->center_freq)))))
+            !freq_is_chan_12_13_14(beacon_chan->center_freq)))
+               return 0;
+
+       spin_lock_bh(&reg_pending_beacons_lock);
+       processing = pending_reg_beacon(beacon_chan);
+       spin_unlock_bh(&reg_pending_beacons_lock);
+
+       if (processing)
                return 0;
 
        reg_beacon = kzalloc(sizeof(struct reg_beacon), gfp);
        if (!reg_beacon)
                return -ENOMEM;
 
-       REG_DBG_PRINT("Found new beacon on "
-                     "frequency: %d MHz (Ch %d) on %s\n",
+       REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
                      beacon_chan->center_freq,
                      ieee80211_frequency_to_channel(beacon_chan->center_freq),
                      wiphy_name(wiphy));
 
        memcpy(&reg_beacon->chan, beacon_chan,
-               sizeof(struct ieee80211_channel));
-
+              sizeof(struct ieee80211_channel));
 
        /*
         * Since we can be called from BH or and non-BH context
@@ -2155,21 +2047,19 @@ static void print_dfs_region(u8 dfs_region)
                pr_info(" DFS Master region JP");
                break;
        default:
-               pr_info(" DFS Master region Uknown");
+               pr_info(" DFS Master region Unknown");
                break;
        }
 }
 
 static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
+       struct regulatory_request *lr = get_last_request();
 
        if (is_intersected_alpha2(rd->alpha2)) {
-
-               if (last_request->initiator ==
-                   NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+               if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                        struct cfg80211_registered_device *rdev;
-                       rdev = cfg80211_rdev_by_wiphy_idx(
-                               last_request->wiphy_idx);
+                       rdev = cfg80211_rdev_by_wiphy_idx(lr->wiphy_idx);
                        if (rdev) {
                                pr_info("Current regulatory domain updated by AP to: %c%c\n",
                                        rdev->country_ie_alpha2[0],
@@ -2178,22 +2068,21 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
                                pr_info("Current regulatory domain intersected:\n");
                } else
                        pr_info("Current regulatory domain intersected:\n");
-       } else if (is_world_regdom(rd->alpha2))
+       } else if (is_world_regdom(rd->alpha2)) {
                pr_info("World regulatory domain updated:\n");
-       else {
+       else {
                if (is_unknown_alpha2(rd->alpha2))
                        pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n");
                else {
-                       if (reg_request_cell_base(last_request))
-                               pr_info("Regulatory domain changed "
-                                       "to country: %c%c by Cell Station\n",
+                       if (reg_request_cell_base(lr))
+                               pr_info("Regulatory domain changed to country: %c%c by Cell Station\n",
                                        rd->alpha2[0], rd->alpha2[1]);
                        else
-                               pr_info("Regulatory domain changed "
-                                       "to country: %c%c\n",
+                               pr_info("Regulatory domain changed to country: %c%c\n",
                                        rd->alpha2[0], rd->alpha2[1]);
                }
        }
+
        print_dfs_region(rd->dfs_region);
        print_rd_rules(rd);
 }
@@ -2207,22 +2096,23 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
 /* Takes ownership of rd only if it doesn't fail */
 static int __set_regdom(const struct ieee80211_regdomain *rd)
 {
+       const struct ieee80211_regdomain *regd;
        const struct ieee80211_regdomain *intersected_rd = NULL;
        struct wiphy *request_wiphy;
+       struct regulatory_request *lr = get_last_request();
+
        /* Some basic sanity checks first */
 
+       if (!reg_is_valid_request(rd->alpha2))
+               return -EINVAL;
+
        if (is_world_regdom(rd->alpha2)) {
-               if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
-                       return -EINVAL;
                update_world_regdomain(rd);
                return 0;
        }
 
        if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
-                       !is_unknown_alpha2(rd->alpha2))
-               return -EINVAL;
-
-       if (!last_request)
+           !is_unknown_alpha2(rd->alpha2))
                return -EINVAL;
 
        /*
@@ -2230,7 +2120,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
         * rd is non static (it means CRDA was present and was used last)
         * and the pending request came in from a country IE
         */
-       if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                /*
                 * If someone else asked us to change the rd lets only bother
                 * checking if the alpha2 changes if CRDA was already called
@@ -2246,29 +2136,23 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
         * internal EEPROM data
         */
 
-       if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
-               return -EINVAL;
-
        if (!is_valid_rd(rd)) {
                pr_err("Invalid regulatory domain detected:\n");
                print_regdomain_info(rd);
                return -EINVAL;
        }
 
-       request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
        if (!request_wiphy &&
-           (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-            last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+           (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+            lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
                schedule_delayed_work(&reg_timeout, 0);
                return -ENODEV;
        }
 
-       if (!last_request->intersect) {
-               int r;
-
-               if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
-                       reset_regdomains(false);
-                       cfg80211_regdomain = rd;
+       if (!lr->intersect) {
+               if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
+                       reset_regdomains(false, rd);
                        return 0;
                }
 
@@ -2284,20 +2168,19 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                if (request_wiphy->regd)
                        return -EALREADY;
 
-               r = reg_copy_regd(&request_wiphy->regd, rd);
-               if (r)
-                       return r;
+               regd = reg_copy_regd(rd);
+               if (IS_ERR(regd))
+                       return PTR_ERR(regd);
 
-               reset_regdomains(false);
-               cfg80211_regdomain = rd;
+               rcu_assign_pointer(request_wiphy->regd, regd);
+               reset_regdomains(false, rd);
                return 0;
        }
 
        /* Intersection requires a bit more work */
 
-       if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-
-               intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
+       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+               intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
                if (!intersected_rd)
                        return -EINVAL;
 
@@ -2306,15 +2189,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                 * However if a driver requested this specific regulatory
                 * domain we keep it for its private use
                 */
-               if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER)
-                       request_wiphy->regd = rd;
+               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER)
+                       rcu_assign_pointer(request_wiphy->regd, rd);
                else
                        kfree(rd);
 
                rd = NULL;
 
-               reset_regdomains(false);
-               cfg80211_regdomain = intersected_rd;
+               reset_regdomains(false, intersected_rd);
 
                return 0;
        }
@@ -2326,15 +2208,15 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 /*
  * Use this call to set the current regulatory domain. Conflicts with
  * multiple drivers can be ironed out later. Caller must've already
- * kmalloc'd the rd structure. Caller must hold cfg80211_mutex
+ * kmalloc'd the rd structure.
  */
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
+       struct regulatory_request *lr;
        int r;
 
-       assert_cfg80211_lock();
-
        mutex_lock(&reg_mutex);
+       lr = get_last_request();
 
        /* Note that this doesn't update the wiphys, this is done below */
        r = __set_regdom(rd);
@@ -2343,23 +2225,25 @@ int set_regdom(const struct ieee80211_regdomain *rd)
                        reg_set_request_processed();
 
                kfree(rd);
-               mutex_unlock(&reg_mutex);
-               return r;
+               goto out;
        }
 
        /* This would make this whole thing pointless */
-       if (!last_request->intersect)
-               BUG_ON(rd != cfg80211_regdomain);
+       if (WARN_ON(!lr->intersect && rd != get_cfg80211_regdom())) {
+               r = -EINVAL;
+               goto out;
+       }
 
        /* update all wiphys now with the new established regulatory domain */
-       update_all_wiphy_regulatory(last_request->initiator);
+       update_all_wiphy_regulatory(lr->initiator);
 
-       print_regdomain(cfg80211_regdomain);
+       print_regdomain(get_cfg80211_regdom());
 
-       nl80211_send_reg_change_event(last_request);
+       nl80211_send_reg_change_event(lr);
 
        reg_set_request_processed();
 
+ out:
        mutex_unlock(&reg_mutex);
 
        return r;
@@ -2367,20 +2251,26 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 
 int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       if (last_request && !last_request->processed) {
-               if (add_uevent_var(env, "COUNTRY=%c%c",
-                                  last_request->alpha2[0],
-                                  last_request->alpha2[1]))
-                       return -ENOMEM;
+       struct regulatory_request *lr;
+       u8 alpha2[2];
+       bool add = false;
+
+       rcu_read_lock();
+       lr = get_last_request();
+       if (lr && !lr->processed) {
+               memcpy(alpha2, lr->alpha2, 2);
+               add = true;
        }
+       rcu_read_unlock();
 
+       if (add)
+               return add_uevent_var(env, "COUNTRY=%c%c",
+                                     alpha2[0], alpha2[1]);
        return 0;
 }
 
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
-       assert_cfg80211_lock();
-
        mutex_lock(&reg_mutex);
 
        if (!reg_dev_ignore_cell_hint(wiphy))
@@ -2395,32 +2285,32 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
 void wiphy_regulatory_deregister(struct wiphy *wiphy)
 {
        struct wiphy *request_wiphy = NULL;
-
-       assert_cfg80211_lock();
+       struct regulatory_request *lr;
 
        mutex_lock(&reg_mutex);
+       lr = get_last_request();
 
        if (!reg_dev_ignore_cell_hint(wiphy))
                reg_num_devs_support_basehint--;
 
-       kfree(wiphy->regd);
+       rcu_free_regdom(get_wiphy_regdom(wiphy));
+       rcu_assign_pointer(wiphy->regd, NULL);
 
-       if (last_request)
-               request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+       if (lr)
+               request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
 
        if (!request_wiphy || request_wiphy != wiphy)
                goto out;
 
-       last_request->wiphy_idx = WIPHY_IDX_STALE;
-       last_request->country_ie_env = ENVIRON_ANY;
+       lr->wiphy_idx = WIPHY_IDX_INVALID;
+       lr->country_ie_env = ENVIRON_ANY;
 out:
        mutex_unlock(&reg_mutex);
 }
 
 static void reg_timeout_work(struct work_struct *work)
 {
-       REG_DBG_PRINT("Timeout while waiting for CRDA to reply, "
-                     "restoring regulatory settings\n");
+       REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
        restore_regulatory_settings(true);
 }
 
@@ -2439,13 +2329,13 @@ int __init regulatory_init(void)
 
        reg_regdb_size_check();
 
-       cfg80211_regdomain = cfg80211_world_regdom;
+       rcu_assign_pointer(cfg80211_regdomain, cfg80211_world_regdom);
 
        user_alpha2[0] = '9';
        user_alpha2[1] = '7';
 
        /* We always try to get an update for the static regdomain */
-       err = regulatory_hint_core(cfg80211_regdomain->alpha2);
+       err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
        if (err) {
                if (err == -ENOMEM)
                        return err;
@@ -2457,10 +2347,6 @@ int __init regulatory_init(void)
                 * errors as non-fatal.
                 */
                pr_err("kobject_uevent_env() was unable to call CRDA during init\n");
-#ifdef CONFIG_CFG80211_REG_DEBUG
-               /* We want to find out exactly why when debugging */
-               WARN_ON(err);
-#endif
        }
 
        /*
@@ -2474,7 +2360,7 @@ int __init regulatory_init(void)
        return 0;
 }
 
-void /* __init_or_exit */ regulatory_exit(void)
+void regulatory_exit(void)
 {
        struct regulatory_request *reg_request, *tmp;
        struct reg_beacon *reg_beacon, *btmp;
@@ -2482,43 +2368,27 @@ void /* __init_or_exit */ regulatory_exit(void)
        cancel_work_sync(&reg_work);
        cancel_delayed_work_sync(&reg_timeout);
 
-       mutex_lock(&cfg80211_mutex);
+       /* Lock to suppress warnings */
        mutex_lock(&reg_mutex);
-
-       reset_regdomains(true);
+       reset_regdomains(true, NULL);
+       mutex_unlock(&reg_mutex);
 
        dev_set_uevent_suppress(&reg_pdev->dev, true);
 
        platform_device_unregister(reg_pdev);
 
-       spin_lock_bh(&reg_pending_beacons_lock);
-       if (!list_empty(&reg_pending_beacons)) {
-               list_for_each_entry_safe(reg_beacon, btmp,
-                                        &reg_pending_beacons, list) {
-                       list_del(&reg_beacon->list);
-                       kfree(reg_beacon);
-               }
+       list_for_each_entry_safe(reg_beacon, btmp, &reg_pending_beacons, list) {
+               list_del(&reg_beacon->list);
+               kfree(reg_beacon);
        }
-       spin_unlock_bh(&reg_pending_beacons_lock);
 
-       if (!list_empty(&reg_beacon_list)) {
-               list_for_each_entry_safe(reg_beacon, btmp,
-                                        &reg_beacon_list, list) {
-                       list_del(&reg_beacon->list);
-                       kfree(reg_beacon);
-               }
+       list_for_each_entry_safe(reg_beacon, btmp, &reg_beacon_list, list) {
+               list_del(&reg_beacon->list);
+               kfree(reg_beacon);
        }
 
-       spin_lock(&reg_requests_lock);
-       if (!list_empty(&reg_requests_list)) {
-               list_for_each_entry_safe(reg_request, tmp,
-                                        &reg_requests_list, list) {
-                       list_del(&reg_request->list);
-                       kfree(reg_request);
-               }
+       list_for_each_entry_safe(reg_request, tmp, &reg_requests_list, list) {
+               list_del(&reg_request->list);
+               kfree(reg_request);
        }
-       spin_unlock(&reg_requests_lock);
-
-       mutex_unlock(&reg_mutex);
-       mutex_unlock(&cfg80211_mutex);
 }
index 4c0a32ffd530daabb18912edb827c968456a26fa..af2d5f8a5d828481e4036cba15d7577674b0e303 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-extern const struct ieee80211_regdomain *cfg80211_regdomain;
+extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
 
 bool is_world_regdom(const char *alpha2);
-bool reg_is_valid_request(const char *alpha2);
 bool reg_supported_dfs_region(u8 dfs_region);
 
 int regulatory_hint_user(const char *alpha2,
@@ -55,8 +54,8 @@ bool reg_last_request_cell_base(void);
  * set the wiphy->disable_beacon_hints to true.
  */
 int regulatory_hint_found_beacon(struct wiphy *wiphy,
-                                       struct ieee80211_channel *beacon_chan,
-                                       gfp_t gfp);
+                                struct ieee80211_channel *beacon_chan,
+                                gfp_t gfp);
 
 /**
  * regulatory_hint_11d - hints a country IE as a regulatory domain
index f2431e41a373d47b12422642b73e00068834cdd7..a825dfe12cf74bfad50ea500b5a96f9018a11a19 100644 (file)
@@ -192,7 +192,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                            prev_bssid,
                                            params->ssid, params->ssid_len,
                                            params->ie, params->ie_len,
-                                           false, &params->crypto,
+                                           params->mfp != NL80211_MFP_NO,
+                                           &params->crypto,
                                            params->flags, &params->ht_capa,
                                            &params->ht_capa_mask);
                if (err)
@@ -519,10 +520,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
         * - country_ie + 2, the start of the country ie data, and
         * - and country_ie[1] which is the IE length
         */
-       regulatory_hint_11d(wdev->wiphy,
-                           bss->channel->band,
-                           country_ie + 2,
-                           country_ie[1]);
+       regulatory_hint_11d(wdev->wiphy, bss->channel->band,
+                           country_ie + 2, country_ie[1]);
        kfree(country_ie);
 }
 
index 16d76a807c2fac022294aa33cb0336bb89bab38b..1c2795d52db0a9d1a6cae01e836918e788be6314 100644 (file)
@@ -1184,7 +1184,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
                                 enum nl80211_iftype iftype,
                                 struct ieee80211_channel *chan,
-                                enum cfg80211_chan_mode chanmode)
+                                enum cfg80211_chan_mode chanmode,
+                                u8 radar_detect)
 {
        struct wireless_dev *wdev_iter;
        u32 used_iftypes = BIT(iftype);
@@ -1195,14 +1196,45 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
        enum cfg80211_chan_mode chmode;
        int num_different_channels = 0;
        int total = 1;
+       bool radar_required;
        int i, j;
 
        ASSERT_RTNL();
        lockdep_assert_held(&rdev->devlist_mtx);
 
+       if (WARN_ON(hweight32(radar_detect) > 1))
+               return -EINVAL;
+
+       switch (iftype) {
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_WDS:
+               radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
+               break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_MONITOR:
+               radar_required = false;
+               break;
+       case NL80211_IFTYPE_P2P_DEVICE:
+       case NUM_NL80211_IFTYPES:
+       case NL80211_IFTYPE_UNSPECIFIED:
+       default:
+               return -EINVAL;
+       }
+
+       if (radar_required && !radar_detect)
+               return -EINVAL;
+
        /* Always allow software iftypes */
-       if (rdev->wiphy.software_iftypes & BIT(iftype))
+       if (rdev->wiphy.software_iftypes & BIT(iftype)) {
+               if (radar_detect)
+                       return -EINVAL;
                return 0;
+       }
 
        memset(num, 0, sizeof(num));
        memset(used_channels, 0, sizeof(used_channels));
@@ -1275,7 +1307,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                used_iftypes |= BIT(wdev_iter->iftype);
        }
 
-       if (total == 1)
+       if (total == 1 && !radar_detect)
                return 0;
 
        for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
@@ -1308,6 +1340,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                        }
                }
 
+               if (radar_detect && !(c->radar_detect_widths & radar_detect))
+                       goto cont;
+
                /*
                 * Finally check that all iftypes that we're currently
                 * using are actually part of this combination. If they
index 4ce2d93162c12acbf1b43577a6e1198af2cba9c5..f9a54955474081733669f3eb8af11ec7fc2432ea 100644 (file)
@@ -700,8 +700,7 @@ void xfrm_probe_algs(void)
        }
 
        for (i = 0; i < ealg_entries(); i++) {
-               status = crypto_has_blkcipher(ealg_list[i].name, 0,
-                                             CRYPTO_ALG_ASYNC);
+               status = crypto_has_ablkcipher(ealg_list[i].name, 0, 0);
                if (ealg_list[i].available != status)
                        ealg_list[i].available = status;
        }
index 95a338c89f99d87af24ffa97faf17e1a7ef700e8..3670526e70b97e804e90404036c89a5e54b5dcf5 100644 (file)
@@ -61,6 +61,12 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
                }
 
                spin_lock_bh(&x->lock);
+
+               if (unlikely(x->km.state != XFRM_STATE_VALID)) {
+                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEINVALID);
+                       goto error_nolock;
+               }
+
                err = xfrm_state_check_expire(x);
                if (err) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEEXPIRED);
index d0a1af8ed5846d07e73c605f0d119b9f8d87d0b4..603903853e89802099ca81aaba6a9f38bc38c161 100644 (file)
@@ -43,6 +43,7 @@ static const struct snmp_mib xfrm_mib_list[] = {
        SNMP_MIB_ITEM("XfrmOutPolDead", LINUX_MIB_XFRMOUTPOLDEAD),
        SNMP_MIB_ITEM("XfrmOutPolError", LINUX_MIB_XFRMOUTPOLERROR),
        SNMP_MIB_ITEM("XfrmFwdHdrError", LINUX_MIB_XFRMFWDHDRERROR),
+       SNMP_MIB_ITEM("XfrmOutStateInvalid", LINUX_MIB_XFRMOUTSTATEINVALID),
        SNMP_MIB_SENTINEL
 };
 
index 3459692092ec1f44220d02a4d73d82613896793d..0adae918a7a24c02838d807c254e2cdb5ec3cdc9 100644 (file)
@@ -158,8 +158,8 @@ out_unlock:
        mutex_unlock(&hash_resize_mutex);
 }
 
-static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
-static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
+static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
+static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
 
 static DEFINE_SPINLOCK(xfrm_state_gc_lock);
 
@@ -168,58 +168,45 @@ int __xfrm_state_delete(struct xfrm_state *x);
 int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
 void km_state_expired(struct xfrm_state *x, int hard, u32 portid);
 
-static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
-{
-       struct xfrm_state_afinfo *afinfo;
-       if (unlikely(family >= NPROTO))
-               return NULL;
-       write_lock_bh(&xfrm_state_afinfo_lock);
-       afinfo = xfrm_state_afinfo[family];
-       if (unlikely(!afinfo))
-               write_unlock_bh(&xfrm_state_afinfo_lock);
-       return afinfo;
-}
-
-static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
-       __releases(xfrm_state_afinfo_lock)
-{
-       write_unlock_bh(&xfrm_state_afinfo_lock);
-}
-
+static DEFINE_SPINLOCK(xfrm_type_lock);
 int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
 {
-       struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
+       struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
        const struct xfrm_type **typemap;
        int err = 0;
 
        if (unlikely(afinfo == NULL))
                return -EAFNOSUPPORT;
        typemap = afinfo->type_map;
+       spin_lock_bh(&xfrm_type_lock);
 
        if (likely(typemap[type->proto] == NULL))
                typemap[type->proto] = type;
        else
                err = -EEXIST;
-       xfrm_state_unlock_afinfo(afinfo);
+       spin_unlock_bh(&xfrm_type_lock);
+       xfrm_state_put_afinfo(afinfo);
        return err;
 }
 EXPORT_SYMBOL(xfrm_register_type);
 
 int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
 {
-       struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
+       struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
        const struct xfrm_type **typemap;
        int err = 0;
 
        if (unlikely(afinfo == NULL))
                return -EAFNOSUPPORT;
        typemap = afinfo->type_map;
+       spin_lock_bh(&xfrm_type_lock);
 
        if (unlikely(typemap[type->proto] != type))
                err = -ENOENT;
        else
                typemap[type->proto] = NULL;
-       xfrm_state_unlock_afinfo(afinfo);
+       spin_unlock_bh(&xfrm_type_lock);
+       xfrm_state_put_afinfo(afinfo);
        return err;
 }
 EXPORT_SYMBOL(xfrm_unregister_type);
@@ -256,6 +243,7 @@ static void xfrm_put_type(const struct xfrm_type *type)
        module_put(type->owner);
 }
 
+static DEFINE_SPINLOCK(xfrm_mode_lock);
 int xfrm_register_mode(struct xfrm_mode *mode, int family)
 {
        struct xfrm_state_afinfo *afinfo;
@@ -265,12 +253,13 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family)
        if (unlikely(mode->encap >= XFRM_MODE_MAX))
                return -EINVAL;
 
-       afinfo = xfrm_state_lock_afinfo(family);
+       afinfo = xfrm_state_get_afinfo(family);
        if (unlikely(afinfo == NULL))
                return -EAFNOSUPPORT;
 
        err = -EEXIST;
        modemap = afinfo->mode_map;
+       spin_lock_bh(&xfrm_mode_lock);
        if (modemap[mode->encap])
                goto out;
 
@@ -283,7 +272,8 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family)
        err = 0;
 
 out:
-       xfrm_state_unlock_afinfo(afinfo);
+       spin_unlock_bh(&xfrm_mode_lock);
+       xfrm_state_put_afinfo(afinfo);
        return err;
 }
 EXPORT_SYMBOL(xfrm_register_mode);
@@ -297,19 +287,21 @@ int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
        if (unlikely(mode->encap >= XFRM_MODE_MAX))
                return -EINVAL;
 
-       afinfo = xfrm_state_lock_afinfo(family);
+       afinfo = xfrm_state_get_afinfo(family);
        if (unlikely(afinfo == NULL))
                return -EAFNOSUPPORT;
 
        err = -ENOENT;
        modemap = afinfo->mode_map;
+       spin_lock_bh(&xfrm_mode_lock);
        if (likely(modemap[mode->encap] == mode)) {
                modemap[mode->encap] = NULL;
                module_put(mode->afinfo->owner);
                err = 0;
        }
 
-       xfrm_state_unlock_afinfo(afinfo);
+       spin_unlock_bh(&xfrm_mode_lock);
+       xfrm_state_put_afinfo(afinfo);
        return err;
 }
 EXPORT_SYMBOL(xfrm_unregister_mode);
@@ -1370,9 +1362,6 @@ int xfrm_state_check_expire(struct xfrm_state *x)
        if (!x->curlft.use_time)
                x->curlft.use_time = get_seconds();
 
-       if (x->km.state != XFRM_STATE_VALID)
-               return -EINVAL;
-
        if (x->curlft.bytes >= x->lft.hard_byte_limit ||
            x->curlft.packets >= x->lft.hard_packet_limit) {
                x->km.state = XFRM_STATE_EXPIRED;
@@ -1648,27 +1637,26 @@ static void xfrm_replay_timer_handler(unsigned long data)
 }
 
 static LIST_HEAD(xfrm_km_list);
-static DEFINE_RWLOCK(xfrm_km_lock);
 
 void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
 {
        struct xfrm_mgr *km;
 
-       read_lock(&xfrm_km_lock);
-       list_for_each_entry(km, &xfrm_km_list, list)
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list)
                if (km->notify_policy)
                        km->notify_policy(xp, dir, c);
-       read_unlock(&xfrm_km_lock);
+       rcu_read_unlock();
 }
 
 void km_state_notify(struct xfrm_state *x, const struct km_event *c)
 {
        struct xfrm_mgr *km;
-       read_lock(&xfrm_km_lock);
-       list_for_each_entry(km, &xfrm_km_list, list)
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list)
                if (km->notify)
                        km->notify(x, c);
-       read_unlock(&xfrm_km_lock);
+       rcu_read_unlock();
 }
 
 EXPORT_SYMBOL(km_policy_notify);
@@ -1698,13 +1686,13 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
        int err = -EINVAL, acqret;
        struct xfrm_mgr *km;
 
-       read_lock(&xfrm_km_lock);
-       list_for_each_entry(km, &xfrm_km_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list) {
                acqret = km->acquire(x, t, pol);
                if (!acqret)
                        err = acqret;
        }
-       read_unlock(&xfrm_km_lock);
+       rcu_read_unlock();
        return err;
 }
 EXPORT_SYMBOL(km_query);
@@ -1714,14 +1702,14 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
        int err = -EINVAL;
        struct xfrm_mgr *km;
 
-       read_lock(&xfrm_km_lock);
-       list_for_each_entry(km, &xfrm_km_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list) {
                if (km->new_mapping)
                        err = km->new_mapping(x, ipaddr, sport);
                if (!err)
                        break;
        }
-       read_unlock(&xfrm_km_lock);
+       rcu_read_unlock();
        return err;
 }
 EXPORT_SYMBOL(km_new_mapping);
@@ -1750,15 +1738,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
        int ret;
        struct xfrm_mgr *km;
 
-       read_lock(&xfrm_km_lock);
-       list_for_each_entry(km, &xfrm_km_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list) {
                if (km->migrate) {
                        ret = km->migrate(sel, dir, type, m, num_migrate, k);
                        if (!ret)
                                err = ret;
                }
        }
-       read_unlock(&xfrm_km_lock);
+       rcu_read_unlock();
        return err;
 }
 EXPORT_SYMBOL(km_migrate);
@@ -1770,15 +1758,15 @@ int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address
        int ret;
        struct xfrm_mgr *km;
 
-       read_lock(&xfrm_km_lock);
-       list_for_each_entry(km, &xfrm_km_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list) {
                if (km->report) {
                        ret = km->report(net, proto, sel, addr);
                        if (!ret)
                                err = ret;
                }
        }
-       read_unlock(&xfrm_km_lock);
+       rcu_read_unlock();
        return err;
 }
 EXPORT_SYMBOL(km_report);
@@ -1802,14 +1790,14 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
                goto out;
 
        err = -EINVAL;
-       read_lock(&xfrm_km_lock);
-       list_for_each_entry(km, &xfrm_km_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list) {
                pol = km->compile_policy(sk, optname, data,
                                         optlen, &err);
                if (err >= 0)
                        break;
        }
-       read_unlock(&xfrm_km_lock);
+       rcu_read_unlock();
 
        if (err >= 0) {
                xfrm_sk_policy_insert(sk, err, pol);
@@ -1823,20 +1811,23 @@ out:
 }
 EXPORT_SYMBOL(xfrm_user_policy);
 
+static DEFINE_SPINLOCK(xfrm_km_lock);
+
 int xfrm_register_km(struct xfrm_mgr *km)
 {
-       write_lock_bh(&xfrm_km_lock);
-       list_add_tail(&km->list, &xfrm_km_list);
-       write_unlock_bh(&xfrm_km_lock);
+       spin_lock_bh(&xfrm_km_lock);
+       list_add_tail_rcu(&km->list, &xfrm_km_list);
+       spin_unlock_bh(&xfrm_km_lock);
        return 0;
 }
 EXPORT_SYMBOL(xfrm_register_km);
 
 int xfrm_unregister_km(struct xfrm_mgr *km)
 {
-       write_lock_bh(&xfrm_km_lock);
-       list_del(&km->list);
-       write_unlock_bh(&xfrm_km_lock);
+       spin_lock_bh(&xfrm_km_lock);
+       list_del_rcu(&km->list);
+       spin_unlock_bh(&xfrm_km_lock);
+       synchronize_rcu();
        return 0;
 }
 EXPORT_SYMBOL(xfrm_unregister_km);
@@ -1848,12 +1839,12 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
                return -EINVAL;
        if (unlikely(afinfo->family >= NPROTO))
                return -EAFNOSUPPORT;
-       write_lock_bh(&xfrm_state_afinfo_lock);
+       spin_lock_bh(&xfrm_state_afinfo_lock);
        if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
                err = -ENOBUFS;
        else
-               xfrm_state_afinfo[afinfo->family] = afinfo;
-       write_unlock_bh(&xfrm_state_afinfo_lock);
+               rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo);
+       spin_unlock_bh(&xfrm_state_afinfo_lock);
        return err;
 }
 EXPORT_SYMBOL(xfrm_state_register_afinfo);
@@ -1865,14 +1856,15 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
                return -EINVAL;
        if (unlikely(afinfo->family >= NPROTO))
                return -EAFNOSUPPORT;
-       write_lock_bh(&xfrm_state_afinfo_lock);
+       spin_lock_bh(&xfrm_state_afinfo_lock);
        if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
                if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
                        err = -EINVAL;
                else
-                       xfrm_state_afinfo[afinfo->family] = NULL;
+                       RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL);
        }
-       write_unlock_bh(&xfrm_state_afinfo_lock);
+       spin_unlock_bh(&xfrm_state_afinfo_lock);
+       synchronize_rcu();
        return err;
 }
 EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
@@ -1882,17 +1874,16 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
        struct xfrm_state_afinfo *afinfo;
        if (unlikely(family >= NPROTO))
                return NULL;
-       read_lock(&xfrm_state_afinfo_lock);
-       afinfo = xfrm_state_afinfo[family];
+       rcu_read_lock();
+       afinfo = rcu_dereference(xfrm_state_afinfo[family]);
        if (unlikely(!afinfo))
-               read_unlock(&xfrm_state_afinfo_lock);
+               rcu_read_unlock();
        return afinfo;
 }
 
 static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
-       __releases(xfrm_state_afinfo_lock)
 {
-       read_unlock(&xfrm_state_afinfo_lock);
+       rcu_read_unlock();
 }
 
 /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
This page took 3.463435 seconds and 5 git commands to generate.